bitkeeper revision 1.1159.187.1 (41a26ec1W-iw8iKd-EuzGrvNLX-08g)
authoriap10@labyrinth.cl.cam.ac.uk <iap10@labyrinth.cl.cam.ac.uk>
Mon, 22 Nov 2004 22:57:05 +0000 (22:57 +0000)
committeriap10@labyrinth.cl.cam.ac.uk <iap10@labyrinth.cl.cam.ac.uk>
Mon, 22 Nov 2004 22:57:05 +0000 (22:57 +0000)
Initial ia64 checkin.

.rootkeys
xen/arch/ia64/privop.c [new file with mode: 0644]
xen/arch/ia64/process.c [new file with mode: 0644]
xen/arch/ia64/regionreg.c [new file with mode: 0644]
xen/arch/ia64/vcpu.c [new file with mode: 0644]
xen/arch/ia64/xenasm.S [new file with mode: 0644]

index 4c1e4176320f028a918f368ac64ba55519ca716d..493a8f693311b061c729f44113d489f98ec8fe3a 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3f72f1bdJPsV3JCnBqs9ddL9tr6D2g xen/COPYING
 3ddb79bcbOVHh38VJzc97-JEGD4dJQ xen/Makefile
 3ddb79bcWnTwYsQRWl_PaneJfa6p0w xen/Rules.mk
+41a26ebcqaSGVQ8qTMwpPwOJSJ7qSw xen/arch/ia64/privop.c
+41a26ebc4BOHDUsT0TSnryPeV2xfRA xen/arch/ia64/process.c
+41a26ebcJ30TFl1v2kR8rqpEBvOtVw xen/arch/ia64/regionreg.c
+41a26ebc--sjlYZQxmIxyCx3jw70qA xen/arch/ia64/vcpu.c
+41a26ebc4jSBGQOuyNIPDST58mNbBw xen/arch/ia64/xenasm.S
 3ddb79bcZbRBzT3elFWSX7u6NtMagQ xen/arch/x86/Makefile
 3ddb79bcBQF85CfLS4i1WGZ4oLLaCA xen/arch/x86/Rules.mk
 3e5636e5FAYZ5_vQnmgwFJfSdmO5Mw xen/arch/x86/acpi.c
diff --git a/xen/arch/ia64/privop.c b/xen/arch/ia64/privop.c
new file mode 100644 (file)
index 0000000..0dfa9c1
--- /dev/null
@@ -0,0 +1,863 @@
+/*
+ * Privileged operation "API" handling functions.
+ * 
+ * Copyright (C) 2004 Hewlett-Packard Co.
+ *     Dan Magenheimer (dan.magenheimer@hp.com)
+ *
+ */
+
+#include <asm/privop.h>
+#include <asm/privify.h>
+#include <asm/vcpu.h>
+#include <asm/processor.h>
+#include <asm/delay.h> // Debug only
+//#include <debug.h>
+
+long priv_verbose=0;
+
+/**************************************************************************
+Hypercall bundle creation
+**************************************************************************/
+
+
+void build_hypercall_bundle(UINT64 *imva, UINT64 breakimm, UINT64 hypnum, UINT64 ret)
+{
+       INST64_A5 slot0;
+       INST64_I19 slot1;
+       INST64_B4 slot2;
+       IA64_BUNDLE bundle;
+
+       // slot1: mov r2 = hypnum (low 20 bits)
+       slot0.inst = 0;
+       slot0.qp = 0; slot0.r1 = 2; slot0.r3 = 0; slot0.major = 0x9;
+       slot0.imm7b = hypnum; slot0.imm9d = hypnum >> 7;
+       slot0.imm5c = hypnum >> 16; slot0.s = 0;
+       // slot1: break breakimm
+       slot1.inst = 0;
+       slot1.qp = 0; slot1.x6 = 0; slot1.x3 = 0; slot1.major = 0x0;
+       slot1.imm20 = breakimm; slot1.i = breakimm >> 20;
+       // if ret slot2: br.ret.sptk.many rp
+       // else slot2: br.cond.sptk.many rp
+       slot2.inst = 0; slot2.qp = 0; slot2.p = 1; slot2.b2 = 0;
+       slot2.wh = 0; slot2.d = 0; slot2.major = 0x0;
+       if (ret) {
+               slot2.btype = 4; slot2.x6 = 0x21;
+       }
+       else {
+               slot2.btype = 0; slot2.x6 = 0x20;
+       }
+       
+       bundle.i64[0] = 0; bundle.i64[1] = 0;
+       bundle.template = 0x11;
+       bundle.slot0 = slot0.inst; bundle.slot2 = slot2.inst;
+       bundle.slot1a = slot1.inst; bundle.slot1b = slot1.inst >> 18;
+       
+       *imva++ = bundle.i64[0]; *imva = bundle.i64[1];
+}
+
+/**************************************************************************
+Privileged operation emulation routines
+**************************************************************************/
+
+IA64FAULT priv_rfi(VCPU *vcpu, INST64 inst)
+{
+       return vcpu_rfi(vcpu);
+}
+
+IA64FAULT priv_bsw0(VCPU *vcpu, INST64 inst)
+{
+       return vcpu_bsw0(vcpu);
+}
+
+IA64FAULT priv_bsw1(VCPU *vcpu, INST64 inst)
+{
+       return vcpu_bsw1(vcpu);
+}
+
+IA64FAULT priv_cover(VCPU *vcpu, INST64 inst)
+{
+       return vcpu_cover(vcpu);
+}
+
+IA64FAULT priv_ptc_l(VCPU *vcpu, INST64 inst)
+{
+       UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3);
+       UINT64 addr_range;
+
+       addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2);
+       return vcpu_ptc_l(vcpu,vadr,addr_range);
+}
+
+IA64FAULT priv_ptc_e(VCPU *vcpu, INST64 inst)
+{
+       UINT src = inst.M28.r3;
+
+       // NOTE: ptc_e with source gr > 63 is emulated as a fc r(y-64)
+       if (src > 63) return(vcpu_fc(vcpu,vcpu_get_gr(vcpu,src - 64)));
+       return vcpu_ptc_e(vcpu,vcpu_get_gr(vcpu,src));
+}
+
+IA64FAULT priv_ptc_g(VCPU *vcpu, INST64 inst)
+{
+       UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3);
+       UINT64 addr_range;
+
+       addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2);
+       return vcpu_ptc_g(vcpu,vadr,addr_range);
+}
+
+IA64FAULT priv_ptc_ga(VCPU *vcpu, INST64 inst)
+{
+       UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3);
+       UINT64 addr_range;
+
+       addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2);
+       return vcpu_ptc_ga(vcpu,vadr,addr_range);
+}
+
+IA64FAULT priv_ptr_d(VCPU *vcpu, INST64 inst)
+{
+       UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3);
+       UINT64 addr_range;
+
+       addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2);
+       return vcpu_ptr_d(vcpu,vadr,addr_range);
+}
+
+IA64FAULT priv_ptr_i(VCPU *vcpu, INST64 inst)
+{
+       UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3);
+       UINT64 addr_range;
+
+       addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2);
+       return vcpu_ptr_i(vcpu,vadr,addr_range);
+}
+
+IA64FAULT priv_tpa(VCPU *vcpu, INST64 inst)
+{
+       UINT64 padr;
+       UINT fault;
+       UINT src = inst.M46.r3;
+
+       // NOTE: tpa with source gr > 63 is emulated as a ttag rx=r(y-64)
+       if (src > 63)
+               fault = vcpu_ttag(vcpu,vcpu_get_gr(vcpu,src-64),&padr);
+       else fault = vcpu_tpa(vcpu,vcpu_get_gr(vcpu,src),&padr);
+       if (fault == IA64_NO_FAULT)
+               return vcpu_set_gr(vcpu, inst.M46.r1, padr);
+       else return fault;
+}
+
+IA64FAULT priv_tak(VCPU *vcpu, INST64 inst)
+{
+       UINT64 key;
+       UINT fault;
+       UINT src = inst.M46.r3;
+
+       // NOTE: tak with source gr > 63 is emulated as a thash rx=r(y-64)
+       if (src > 63)
+               fault = vcpu_thash(vcpu,vcpu_get_gr(vcpu,src-64),&key);
+       else fault = vcpu_tak(vcpu,vcpu_get_gr(vcpu,src),&key);
+       if (fault == IA64_NO_FAULT)
+               return vcpu_set_gr(vcpu, inst.M46.r1, key);
+       else return fault;
+}
+
+/************************************
+ * Insert translation register/cache
+************************************/
+
+IA64FAULT priv_itr_d(VCPU *vcpu, INST64 inst)
+{
+       UINT64 fault, itir, ifa, pte, slot;
+
+       //if (!vcpu_get_psr_ic(vcpu)) return(IA64_ILLOP_FAULT);
+       if ((fault = vcpu_get_itir(vcpu,&itir)) != IA64_NO_FAULT)
+               return(IA64_ILLOP_FAULT);
+       if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT)
+               return(IA64_ILLOP_FAULT);
+       pte = vcpu_get_gr(vcpu,inst.M42.r2);
+       slot = vcpu_get_gr(vcpu,inst.M42.r3);
+
+       return (vcpu_itr_d(vcpu,slot,pte,itir,ifa));
+}
+
+IA64FAULT priv_itr_i(VCPU *vcpu, INST64 inst)
+{
+       UINT64 fault, itir, ifa, pte, slot;
+
+       //if (!vcpu_get_psr_ic(vcpu)) return(IA64_ILLOP_FAULT);
+       if ((fault = vcpu_get_itir(vcpu,&itir)) != IA64_NO_FAULT)
+               return(IA64_ILLOP_FAULT);
+       if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT)
+               return(IA64_ILLOP_FAULT);
+       pte = vcpu_get_gr(vcpu,inst.M42.r2);
+       slot = vcpu_get_gr(vcpu,inst.M42.r3);
+
+       return (vcpu_itr_i(vcpu,slot,pte,itir,ifa));
+}
+
+IA64FAULT priv_itc_d(VCPU *vcpu, INST64 inst)
+{
+       UINT64 fault, itir, ifa, pte;
+
+       //if (!vcpu_get_psr_ic(vcpu)) return(IA64_ILLOP_FAULT);
+       if ((fault = vcpu_get_itir(vcpu,&itir)) != IA64_NO_FAULT)
+               return(IA64_ILLOP_FAULT);
+       if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT)
+               return(IA64_ILLOP_FAULT);
+       pte = vcpu_get_gr(vcpu,inst.M41.r2);
+
+       return (vcpu_itc_d(vcpu,pte,itir,ifa));
+}
+
+IA64FAULT priv_itc_i(VCPU *vcpu, INST64 inst)
+{
+       UINT64 fault, itir, ifa, pte;
+
+       //if (!vcpu_get_psr_ic(vcpu)) return(IA64_ILLOP_FAULT);
+       if ((fault = vcpu_get_itir(vcpu,&itir)) != IA64_NO_FAULT)
+               return(IA64_ILLOP_FAULT);
+       if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT)
+               return(IA64_ILLOP_FAULT);
+       pte = vcpu_get_gr(vcpu,inst.M41.r2);
+
+       return (vcpu_itc_i(vcpu,pte,itir,ifa));
+}
+
+/*************************************
+ * Moves to semi-privileged registers
+*************************************/
+
+IA64FAULT priv_mov_to_ar_imm(VCPU *vcpu, INST64 inst)
+{
+       // I27 and M30 are identical for these fields
+       UINT64 ar3 = inst.M30.ar3;
+       UINT64 imm = vcpu_get_gr(vcpu,inst.M30.imm);
+       return (vcpu_set_ar(vcpu,ar3,imm));
+}
+
+IA64FAULT priv_mov_to_ar_reg(VCPU *vcpu, INST64 inst)
+{
+       // I26 and M29 are identical for these fields
+       UINT64 ar3 = inst.M29.ar3;
+
+       if (inst.M29.r2 > 63 && inst.M29.ar3 < 8) { // privified mov from kr
+               UINT64 val;
+               if (vcpu_get_ar(vcpu,ar3,&val) != IA64_ILLOP_FAULT)
+                       return vcpu_set_gr(vcpu, inst.M29.r2-64, val);
+               else return IA64_ILLOP_FAULT;
+       }
+       else {
+               UINT64 r2 = vcpu_get_gr(vcpu,inst.M29.r2);
+               return (vcpu_set_ar(vcpu,ar3,r2));
+       }
+}
+
+/********************************
+ * Moves to privileged registers
+********************************/
+
+IA64FAULT priv_mov_to_pkr(VCPU *vcpu, INST64 inst)
+{
+       UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
+       UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
+       return (vcpu_set_pkr(vcpu,r3,r2));
+}
+
+IA64FAULT priv_mov_to_rr(VCPU *vcpu, INST64 inst)
+{
+       UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
+       UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
+       return (vcpu_set_rr(vcpu,r3,r2));
+}
+
+IA64FAULT priv_mov_to_dbr(VCPU *vcpu, INST64 inst)
+{
+       UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
+       UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
+       return (vcpu_set_dbr(vcpu,r3,r2));
+}
+
+IA64FAULT priv_mov_to_ibr(VCPU *vcpu, INST64 inst)
+{
+       UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
+       UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
+       return (vcpu_set_ibr(vcpu,r3,r2));
+}
+
+IA64FAULT priv_mov_to_pmc(VCPU *vcpu, INST64 inst)
+{
+       UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
+       UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
+       return (vcpu_set_pmc(vcpu,r3,r2));
+}
+
+IA64FAULT priv_mov_to_pmd(VCPU *vcpu, INST64 inst)
+{
+       UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3);
+       UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2);
+       return (vcpu_set_pmd(vcpu,r3,r2));
+}
+
+unsigned long to_cr_cnt[128] = { 0 };
+
+IA64FAULT priv_mov_to_cr(VCPU *vcpu, INST64 inst)
+{
+       UINT64 val = vcpu_get_gr(vcpu, inst.M32.r2);
+       to_cr_cnt[inst.M32.cr3]++;
+       switch (inst.M32.cr3) {
+           case 0: return vcpu_set_dcr(vcpu,val);
+           case 1: return vcpu_set_itm(vcpu,val);
+           case 2: return vcpu_set_iva(vcpu,val);
+           case 8: return vcpu_set_pta(vcpu,val);
+           case 16:return vcpu_set_ipsr(vcpu,val);
+           case 17:return vcpu_set_isr(vcpu,val);
+           case 19:return vcpu_set_iip(vcpu,val);
+           case 20:return vcpu_set_ifa(vcpu,val);
+           case 21:return vcpu_set_itir(vcpu,val);
+           case 22:return vcpu_set_iipa(vcpu,val);
+           case 23:return vcpu_set_ifs(vcpu,val);
+           case 24:return vcpu_set_iim(vcpu,val);
+           case 25:return vcpu_set_iha(vcpu,val);
+           case 64:return vcpu_set_lid(vcpu,val);
+           case 65:return IA64_ILLOP_FAULT;
+           case 66:return vcpu_set_tpr(vcpu,val);
+           case 67:return vcpu_set_eoi(vcpu,val);
+           case 68:return IA64_ILLOP_FAULT;
+           case 69:return IA64_ILLOP_FAULT;
+           case 70:return IA64_ILLOP_FAULT;
+           case 71:return IA64_ILLOP_FAULT;
+           case 72:return vcpu_set_itv(vcpu,val);
+           case 73:return vcpu_set_pmv(vcpu,val);
+           case 74:return vcpu_set_cmcv(vcpu,val);
+           case 80:return vcpu_set_lrr0(vcpu,val);
+           case 81:return vcpu_set_lrr1(vcpu,val);
+           default: return IA64_ILLOP_FAULT;
+       }
+}
+
+IA64FAULT priv_rsm(VCPU *vcpu, INST64 inst)
+{
+       UINT64 imm24 = (inst.M44.i<<23)|(inst.M44.i2<<21)|inst.M44.imm;
+       return vcpu_reset_psr_sm(vcpu,imm24);
+}
+
+IA64FAULT priv_ssm(VCPU *vcpu, INST64 inst)
+{
+       UINT64 imm24 = (inst.M44.i<<23)|(inst.M44.i2<<21)|inst.M44.imm;
+       return vcpu_set_psr_sm(vcpu,imm24);
+}
+
+/**
+ * @todo Check for reserved bits and return IA64_RSVDREG_FAULT.
+ */
+IA64FAULT priv_mov_to_psr(VCPU *vcpu, INST64 inst)
+{
+       UINT64 val = vcpu_get_gr(vcpu, inst.M35.r2);
+       return vcpu_set_psr_l(vcpu,val);
+}
+
+/**********************************
+ * Moves from privileged registers
+ **********************************/
+
+IA64FAULT priv_mov_from_rr(VCPU *vcpu, INST64 inst)
+{
+       UINT64 val;
+       IA64FAULT fault;
+       
+       if (inst.M43.r1 > 63) { // privified mov from cpuid
+               fault = vcpu_get_cpuid(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val);
+               if (fault == IA64_NO_FAULT)
+                       return vcpu_set_gr(vcpu, inst.M43.r1-64, val);
+       }
+       else {
+               fault = vcpu_get_rr(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val);
+               if (fault == IA64_NO_FAULT)
+                       return vcpu_set_gr(vcpu, inst.M43.r1, val);
+       }
+       return fault;
+}
+
+IA64FAULT priv_mov_from_pkr(VCPU *vcpu, INST64 inst)
+{
+       UINT64 val;
+       IA64FAULT fault;
+       
+       fault = vcpu_get_pkr(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val);
+       if (fault == IA64_NO_FAULT)
+               return vcpu_set_gr(vcpu, inst.M43.r1, val);
+       else return fault;
+}
+
+IA64FAULT priv_mov_from_dbr(VCPU *vcpu, INST64 inst)
+{
+       UINT64 val;
+       IA64FAULT fault;
+       
+       fault = vcpu_get_dbr(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val);
+       if (fault == IA64_NO_FAULT)
+               return vcpu_set_gr(vcpu, inst.M43.r1, val);
+       else return fault;
+}
+
+IA64FAULT priv_mov_from_ibr(VCPU *vcpu, INST64 inst)
+{
+       UINT64 val;
+       IA64FAULT fault;
+       
+       fault = vcpu_get_ibr(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val);
+       if (fault == IA64_NO_FAULT)
+               return vcpu_set_gr(vcpu, inst.M43.r1, val);
+       else return fault;
+}
+
+IA64FAULT priv_mov_from_pmc(VCPU *vcpu, INST64 inst)
+{
+       UINT64 val;
+       IA64FAULT fault;
+       
+       fault = vcpu_get_pmc(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val);
+       if (fault == IA64_NO_FAULT)
+               return vcpu_set_gr(vcpu, inst.M43.r1, val);
+       else return fault;
+}
+
+unsigned long from_cr_cnt[128] = { 0 };
+
+#define cr_get(cr) \
+       ((fault = vcpu_get_##cr(vcpu,&val)) == IA64_NO_FAULT) ? \
+               vcpu_set_gr(vcpu, tgt, val) : fault;
+       
+IA64FAULT priv_mov_from_cr(VCPU *vcpu, INST64 inst)
+{
+       UINT64 tgt = inst.M33.r1;
+       UINT64 val;
+       IA64FAULT fault;
+
+       from_cr_cnt[inst.M33.cr3]++;
+       switch (inst.M33.cr3) {
+           case 0: return cr_get(dcr);
+           case 1: return cr_get(itm);
+           case 2: return cr_get(iva);
+           case 8: return cr_get(pta);
+           case 16:return cr_get(ipsr);
+           case 17:return cr_get(isr);
+           case 19:return cr_get(iip);
+           case 20:return cr_get(ifa);
+           case 21:return cr_get(itir);
+           case 22:return cr_get(iipa);
+           case 23:return cr_get(ifs);
+           case 24:return cr_get(iim);
+           case 25:return cr_get(iha);
+           case 64:return cr_get(lid);
+           case 65:return cr_get(ivr);
+           case 66:return cr_get(tpr);
+           case 67:return vcpu_set_gr(vcpu,tgt,0L);
+           case 68:return cr_get(irr0);
+           case 69:return cr_get(irr1);
+           case 70:return cr_get(irr2);
+           case 71:return cr_get(irr3);
+           case 72:return cr_get(itv);
+           case 73:return cr_get(pmv);
+           case 74:return cr_get(cmcv);
+           case 80:return cr_get(lrr0);
+           case 81:return cr_get(lrr1);
+           default: return IA64_ILLOP_FAULT;
+       }
+       return IA64_ILLOP_FAULT;
+}
+
+IA64FAULT priv_mov_from_psr(VCPU *vcpu, INST64 inst)
+{
+       UINT64 tgt = inst.M33.r1;
+       UINT64 val;
+       IA64FAULT fault;
+
+       if ((fault = vcpu_get_psr(vcpu,&val)) == IA64_NO_FAULT)
+               return vcpu_set_gr(vcpu, tgt, val);
+       else return fault;
+}
+
+/**************************************************************************
+Privileged operation decode and dispatch routines
+**************************************************************************/
+
+IA64_SLOT_TYPE slot_types[0x20][3] = {
+       {M, I, I}, {M, I, I}, {M, I, I}, {M, I, I},
+       {M, I, ILLEGAL}, {M, I, ILLEGAL},
+       {ILLEGAL, ILLEGAL, ILLEGAL}, {ILLEGAL, ILLEGAL, ILLEGAL},
+       {M, M, I}, {M, M, I}, {M, M, I}, {M, M, I},
+       {M, F, I}, {M, F, I},
+       {M, M, F}, {M, M, F},
+       {M, I, B}, {M, I, B},
+       {M, B, B}, {M, B, B},
+       {ILLEGAL, ILLEGAL, ILLEGAL}, {ILLEGAL, ILLEGAL, ILLEGAL},
+       {B, B, B}, {B, B, B},
+       {M, M, B}, {M, M, B},
+       {ILLEGAL, ILLEGAL, ILLEGAL}, {ILLEGAL, ILLEGAL, ILLEGAL},
+       {M, F, B}, {M, F, B},
+       {ILLEGAL, ILLEGAL, ILLEGAL}, {ILLEGAL, ILLEGAL, ILLEGAL}
+};
+
+// pointer to privileged emulation function
+typedef IA64FAULT (*PPEFCN)(VCPU *vcpu, INST64 inst);
+
+PPEFCN Mpriv_funcs[64] = {
+  priv_mov_to_rr, priv_mov_to_dbr, priv_mov_to_ibr, priv_mov_to_pkr,
+  priv_mov_to_pmc, priv_mov_to_pmd, 0, 0,
+  0, priv_ptc_l, priv_ptc_g, priv_ptc_ga,
+  priv_ptr_d, priv_ptr_i, priv_itr_d, priv_itr_i,
+  priv_mov_from_rr, priv_mov_from_dbr, priv_mov_from_ibr, priv_mov_from_pkr,
+  priv_mov_from_pmc, 0, 0, 0,
+  0, 0, 0, 0,
+  0, 0, priv_tpa, priv_tak,
+  0, 0, 0, 0,
+  priv_mov_from_cr, priv_mov_from_psr, 0, 0,
+  0, 0, 0, 0,
+  priv_mov_to_cr, priv_mov_to_psr, priv_itc_d, priv_itc_i,
+  0, 0, 0, 0,
+  priv_ptc_e, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0
+};
+
+struct {
+       unsigned long mov_to_ar_imm;
+       unsigned long mov_to_ar_reg;
+       unsigned long ssm;
+       unsigned long rsm;
+       unsigned long rfi;
+       unsigned long bsw0;
+       unsigned long bsw1;
+       unsigned long cover;
+       unsigned long Mpriv_cnt[64];
+} privcnt = { 0 };
+
+unsigned long privop_trace = 0;
+
+IA64FAULT
+priv_handle_op(VCPU *vcpu, REGS *regs, int privlvl)
+{
+       IA64_BUNDLE bundle, __get_domain_bundle(UINT64);
+       int slot;
+       IA64_SLOT_TYPE slot_type;
+       INST64 inst;
+       PPEFCN pfunc;
+       unsigned long ipsr = regs->cr_ipsr;
+       UINT64 iip = regs->cr_iip;
+       int x6;
+       
+       // make a local copy of the bundle containing the privop
+#if 1
+       bundle = __get_domain_bundle(iip);
+       if (!bundle.i64[0] && !bundle.i64[1]) return IA64_RETRY;
+#else
+#ifdef AVOIDING_POSSIBLE_DOMAIN_TLB_MISS
+       //TODO: this needs to check for faults and behave accordingly
+       if (!vcpu_get_iip_bundle(&bundle)) return IA64_DTLB_FAULT;
+#else
+if (iip < 0x10000) {
+ printf("priv_handle_op: unlikely iip=%p,b0=%p\n",iip,regs->b0);
+ dummy();
+}
+        bundle = *(IA64_BUNDLE *)iip;
+#endif
+#endif
+#if 0
+       if (iip==0xa000000100001820) {
+               static int firstpagefault = 1;
+               if (firstpagefault) {
+                       printf("*** First time to domain page fault!\n");                               firstpagefault=0;
+               }
+       }
+#endif
+       if (privop_trace) {
+               static long i = 400;
+               //if (i > 0) printf("privop @%p\n",iip);
+               if (i > 0) printf("priv_handle_op: @%p, itc=%lx, itm=%lx\n",
+                       iip,ia64_get_itc(),ia64_get_itm());
+               i--;
+       }
+       slot = ((struct ia64_psr *)&ipsr)->ri;
+       if (!slot) inst.inst = (bundle.i64[0]>>5) & MASK_41;
+       else if (slot == 1)
+               inst.inst = ((bundle.i64[0]>>46) | bundle.i64[1]<<18) & MASK_41;
+       else if (slot == 2) inst.inst = (bundle.i64[1]>>23) & MASK_41; 
+       else printf("priv_handle_op: illegal slot: %d\n", slot);
+
+       slot_type = slot_types[bundle.template][slot];
+       if (priv_verbose) {
+               printf("priv_handle_op: checking bundle at 0x%lx (op=0x%016lx) slot %d (type=%d)\n",
+                iip, (UINT64)inst.inst, slot, slot_type);
+       }
+       if (slot_type == B && inst.generic.major == 0 && inst.B8.x6 == 0x0) {
+               // break instr for privified cover
+       }
+       else if (privlvl != 2) return (IA64_ILLOP_FAULT);
+       switch (slot_type) {
+           case M:
+               if (inst.generic.major == 0) {
+#if 0
+                       if (inst.M29.x6 == 0 && inst.M29.x3 == 0) {
+                               privcnt.cover++;
+                               return priv_cover(vcpu,inst);
+                       }
+#endif
+                       if (inst.M29.x3 != 0) break;
+                       if (inst.M30.x4 == 8 && inst.M30.x2 == 2) {
+                               privcnt.mov_to_ar_imm++;
+                               return priv_mov_to_ar_imm(vcpu,inst);
+                       }
+                       if (inst.M44.x4 == 6) {
+                               privcnt.ssm++;
+                               return priv_ssm(vcpu,inst);
+                       }
+                       if (inst.M44.x4 == 7) {
+                               privcnt.rsm++;
+                               return priv_rsm(vcpu,inst);
+                       }
+                       break;
+               }
+               else if (inst.generic.major != 1) break;
+               x6 = inst.M29.x6;
+               if (x6 == 0x2a) {
+                       privcnt.mov_to_ar_reg++;
+                       return priv_mov_to_ar_reg(vcpu,inst);
+               }
+               if (inst.M29.x3 != 0) break;
+               if (!(pfunc = Mpriv_funcs[x6])) break;
+               if (x6 == 0x1e || x6 == 0x1f)  { // tpa or tak are "special"
+                       if (inst.M46.r3 > 63) {
+                               if (x6 == 0x1e) x6 = 0x1b;
+                               else x6 = 0x1a;
+                       }
+               }
+               privcnt.Mpriv_cnt[x6]++;
+               return (*pfunc)(vcpu,inst);
+               break;
+           case B:
+               if (inst.generic.major != 0) break;
+               if (inst.B8.x6 == 0x08) {
+                       IA64FAULT fault;
+                       privcnt.rfi++;
+                       fault = priv_rfi(vcpu,inst);
+                       if (fault == IA64_NO_FAULT) fault = IA64_RFI_IN_PROGRESS;
+                       return fault;
+               }
+               if (inst.B8.x6 == 0x0c) {
+                       privcnt.bsw0++;
+                       return priv_bsw0(vcpu,inst);
+               }
+               if (inst.B8.x6 == 0x0d) {
+                       privcnt.bsw1++;
+                       return priv_bsw1(vcpu,inst);
+               }
+               if (inst.B8.x6 == 0x0) { // break instr for privified cover
+                       privcnt.cover++;
+                       return priv_cover(vcpu,inst);
+               }
+               break;
+           case I:
+               if (inst.generic.major != 0) break;
+#if 0
+               if (inst.I26.x6 == 0 && inst.I26.x3 == 0) {
+                       privcnt.cover++;
+                       return priv_cover(vcpu,inst);
+               }
+#endif
+               if (inst.I26.x3 != 0) break;  // I26.x3 == I27.x3
+               if (inst.I26.x6 == 0x2a) {
+                       privcnt.mov_to_ar_reg++;
+                       return priv_mov_to_ar_reg(vcpu,inst);
+               }
+               if (inst.I27.x6 == 0x0a) {
+                       privcnt.mov_to_ar_imm++;
+                       return priv_mov_to_ar_imm(vcpu,inst);
+               }
+               break;
+           default:
+               break;
+       }
+        //printf("We who are about do die salute you\n");
+       printf("handle_op: can't handle privop at 0x%lx (op=0x%016lx) slot %d (type=%d)\n",
+                iip, (UINT64)inst.inst, slot, slot_type);
+        //printf("vtop(0x%lx)==0x%lx\r\n", iip, tr_vtop(iip));
+        //thread_mozambique("privop fault\n");
+       return (IA64_ILLOP_FAULT);
+}
+
+/** Emulate a privileged operation.
+ *
+ * This should probably return 0 on success and the "trap number"
+ * (e.g. illegal operation for bad register, priv op for an
+ * instruction that isn't allowed, etc.) on "failure"
+ *
+ * @param vcpu virtual cpu
+ * @param isrcode interrupt service routine code
+ * @return fault
+ */
+IA64FAULT
+priv_emulate(VCPU *vcpu, REGS *regs, UINT64 isr)
+{
+       IA64FAULT fault;
+       UINT64 ipsr = regs->cr_ipsr;
+       UINT64 isrcode = (isr >> 4) & 0xf;
+       int privlvl;
+
+       // handle privops masked as illops? and breaks (6)
+       if (isrcode != 1 && isrcode != 2 && isrcode != 0 && isrcode != 6) {
+               printf("priv_emulate: isrcode != 0 or 1 or 2\n");
+               printf("priv_emulate: returning ILLOP, not implemented!\n");
+               while (1);
+               return IA64_ILLOP_FAULT;
+       }
+       //if (isrcode != 1 && isrcode != 2) return 0;
+       vcpu_set_regs(vcpu,regs);
+       privlvl = (ipsr & IA64_PSR_CPL) >> IA64_PSR_CPL0_BIT;
+       // its OK for a privified-cover to be executed in user-land
+       fault = priv_handle_op(vcpu,regs,privlvl);
+       if (fault == IA64_NO_FAULT) { // success!!
+               // update iip/ipsr to point to the next instruction
+               (void)vcpu_increment_iip(vcpu);
+       }
+       else if (fault == IA64_EXTINT_VECTOR) {
+               // update iip/ipsr before delivering interrupt
+               (void)vcpu_increment_iip(vcpu);
+       }
+       else if (fault == IA64_RFI_IN_PROGRESS) return fault;
+               // success but don't update to next instruction
+        else if (fault == IA64_RETRY) {
+            //printf("Priv emulate gets IA64_RETRY\n");
+           //printf("priv_emulate: returning RETRY, not implemented!\n");
+           //while (1);
+           // don't update iip/ipsr, deliver 
+       
+            vcpu_force_data_miss(vcpu,regs->cr_iip);
+           return IA64_RETRY;
+        }
+       else if (priv_verbose) printf("unhandled operation from handle_op\n");
+//     if (fault == IA64_ILLOP_FAULT) {
+//             printf("priv_emulate: returning ILLOP, not implemented!\n");
+//             while (1);
+//     }
+       return fault;
+}
+
+
+/**************************************************************************
+Privileged operation instrumentation routines
+**************************************************************************/
+
+char *Mpriv_str[64] = {
+  "mov_to_rr", "mov_to_dbr", "mov_to_ibr", "mov_to_pkr",
+  "mov_to_pmc", "mov_to_pmd", "<0x06>", "<0x07>",
+  "<0x08>", "ptc_l", "ptc_g", "ptc_ga",
+  "ptr_d", "ptr_i", "itr_d", "itr_i",
+  "mov_from_rr", "mov_from_dbr", "mov_from_ibr", "mov_from_pkr",
+  "mov_from_pmc", "<0x15>", "<0x16>", "<0x17>",
+  "<0x18>", "<0x19>", "privified-thash", "privified-ttag",
+  "<0x1c>", "<0x1d>", "tpa", "tak",
+  "<0x20>", "<0x21>", "<0x22>", "<0x23>",
+  "mov_from_cr", "mov_from_psr", "<0x26>", "<0x27>",
+  "<0x28>", "<0x29>", "<0x2a>", "<0x2b>",
+  "mov_to_cr", "mov_to_psr", "itc_d", "itc_i",
+  "<0x30>", "<0x31>", "<0x32>", "<0x33>",
+  "ptc_e", "<0x35>", "<0x36>", "<0x37>",
+  "<0x38>", "<0x39>", "<0x3a>", "<0x3b>",
+  "<0x3c>", "<0x3d>", "<0x3e>", "<0x3f>"
+};
+
+#define RS "Rsvd"
+char *cr_str[128] = {
+  "dcr","itm","iva",RS,RS,RS,RS,RS,
+  "pta",RS,RS,RS,RS,RS,RS,RS,
+  "ipsr","isr",RS,"iip","ifa","itir","iipa","ifs",
+  "iim","iha",RS,RS,RS,RS,RS,RS,
+  RS,RS,RS,RS,RS,RS,RS,RS, RS,RS,RS,RS,RS,RS,RS,RS,
+  RS,RS,RS,RS,RS,RS,RS,RS, RS,RS,RS,RS,RS,RS,RS,RS,
+  "lid","ivr","tpr","eoi","irr0","irr1","irr2","irr3",
+  "itv","pmv","cmcv",RS,RS,RS,RS,RS,
+  "lrr0","lrr1",RS,RS,RS,RS,RS,RS,
+  RS,RS,RS,RS,RS,RS,RS,RS, RS,RS,RS,RS,RS,RS,RS,RS,
+  RS,RS,RS,RS,RS,RS,RS,RS, RS,RS,RS,RS,RS,RS,RS,RS,
+  RS,RS,RS,RS,RS,RS,RS,RS
+};
+
+void dump_privop_counts(void)
+{
+       int i, j;
+       UINT64 sum = 0;
+
+       // this is ugly and should probably produce sorted output
+       // but it will have to do for now
+       sum += privcnt.mov_to_ar_imm; sum += privcnt.mov_to_ar_reg;
+       sum += privcnt.ssm; sum += privcnt.rsm;
+       sum += privcnt.rfi; sum += privcnt.bsw0;
+       sum += privcnt.bsw1; sum += privcnt.cover;
+       for (i=0; i < 64; i++) sum += privcnt.Mpriv_cnt[i];
+       printf("Privop statistics: (Total privops: %ld)\r\n",sum);
+       if (privcnt.mov_to_ar_imm)
+               printf("%10d  %s [%d%%]\r\n", privcnt.mov_to_ar_imm,
+                       "mov_to_ar_imm", (privcnt.mov_to_ar_imm*100L)/sum);
+       if (privcnt.mov_to_ar_reg)
+               printf("%10d  %s [%d%%]\r\n", privcnt.mov_to_ar_reg,
+                       "mov_to_ar_reg", (privcnt.mov_to_ar_reg*100L)/sum);
+       if (privcnt.ssm)
+               printf("%10d  %s [%d%%]\r\n", privcnt.ssm,
+                       "ssm", (privcnt.ssm*100L)/sum);
+       if (privcnt.rsm)
+               printf("%10d  %s [%d%%]\r\n", privcnt.rsm,
+                       "rsm", (privcnt.rsm*100L)/sum);
+       if (privcnt.rfi)
+               printf("%10d  %s [%d%%]\r\n", privcnt.rfi,
+                       "rfi", (privcnt.rfi*100L)/sum);
+       if (privcnt.bsw0)
+               printf("%10d  %s [%d%%]\r\n", privcnt.bsw0,
+                       "bsw0", (privcnt.bsw0*100L)/sum);
+       if (privcnt.bsw1)
+               printf("%10d  %s [%d%%]\r\n", privcnt.bsw1,
+                       "bsw1", (privcnt.bsw1*100L)/sum);
+       if (privcnt.cover)
+               printf("%10d  %s [%d%%]\r\n", privcnt.cover,
+                       "cover", (privcnt.cover*100L)/sum);
+       for (i=0; i < 64; i++) if (privcnt.Mpriv_cnt[i]) {
+               if (!Mpriv_str[i]) printf("PRIVSTRING NULL!!\r\n");
+               else printf("%10d  %s [%d%%]\r\n", privcnt.Mpriv_cnt[i],
+                       Mpriv_str[i], (privcnt.Mpriv_cnt[i]*100L)/sum);
+               if (i == 0x24) { // mov from CR
+                       printf("            [");
+                       for (j=0; j < 128; j++) if (from_cr_cnt[j]) {
+                               if (!cr_str[j])
+                                       printf("PRIVSTRING NULL!!\r\n");
+                               printf("%s(%d),",cr_str[j],from_cr_cnt[j]);
+                       }
+                       printf("]\r\n");
+               }
+               else if (i == 0x2c) { // mov to CR
+                       printf("            [");
+                       for (j=0; j < 128; j++) if (to_cr_cnt[j]) {
+                               if (!cr_str[j])
+                                       printf("PRIVSTRING NULL!!\r\n");
+                               printf("%s(%d),",cr_str[j],to_cr_cnt[j]);
+                       }
+                       printf("]\r\n");
+               }
+       }
+}
+
+void zero_privop_counts(void)
+{
+       int i, j;
+
+       // this is ugly and should probably produce sorted output
+       // but it will have to do for now
+       printf("Zeroing privop statistics\r\n");
+       privcnt.mov_to_ar_imm = 0; privcnt.mov_to_ar_reg = 0;
+       privcnt.ssm = 0; privcnt.rsm = 0;
+       privcnt.rfi = 0; privcnt.bsw0 = 0;
+       privcnt.bsw1 = 0; privcnt.cover = 0;
+       for (i=0; i < 64; i++) privcnt.Mpriv_cnt[i] = 0;
+       for (j=0; j < 128; j++) from_cr_cnt[j] = 0;
+       for (j=0; j < 128; j++) to_cr_cnt[j] = 0;
+}
diff --git a/xen/arch/ia64/process.c b/xen/arch/ia64/process.c
new file mode 100644 (file)
index 0000000..9201446
--- /dev/null
@@ -0,0 +1,836 @@
+/*
+ * Miscellaneous process/domain related routines
+ * 
+ * Copyright (C) 2004 Hewlett-Packard Co.
+ *     Dan Magenheimer (dan.magenheimer@hp.com)
+ *
+ */
+
+#include <xen/config.h>
+#include <xen/lib.h>
+#include <xen/errno.h>
+#include <xen/sched.h>
+#include <xen/smp.h>
+#include <asm/ptrace.h>
+#include <xen/delay.h>
+
+#include <linux/efi.h> /* FOR EFI_UNIMPLEMENTED */
+#include <asm/sal.h>   /* FOR struct ia64_sal_retval */
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/desc.h>
+#include <asm/ldt.h>
+#include <xen/irq.h>
+#include <xen/event.h>
+#include <asm/regionreg.h>
+#include <asm/privop.h>
+#include <asm/vcpu.h>
+#include <asm/ia64_int.h>
+#include <asm/hpsim_ssc.h>
+#include <asm/dom_fw.h>
+
+extern struct ia64_sal_retval pal_emulator_static(UINT64);
+extern struct ia64_sal_retval sal_emulator(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64);
+
+extern unsigned long dom0_start, dom0_size;
+
+#define IA64_PSR_CPL1  (__IA64_UL(1) << IA64_PSR_CPL1_BIT)
+// note IA64_PSR_PK removed from following, why is this necessary?
+#define        DELIVER_PSR_SET (IA64_PSR_IC | IA64_PSR_I | \
+                       IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_CPL1 | \
+                       IA64_PSR_IT | IA64_PSR_BN)
+
+#define        DELIVER_PSR_CLR (IA64_PSR_AC | IA64_PSR_DFL | IA64_PSR_DFH | \
+                       IA64_PSR_SP | IA64_PSR_DI | IA64_PSR_SI |       \
+                       IA64_PSR_DB | IA64_PSR_LP | IA64_PSR_TB | \
+                       IA64_PSR_CPL | IA64_PSR_MC | IA64_PSR_IS | \
+                       IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | \
+                       IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | IA64_PSR_IA)
+
+#define PSCB(x)        x->shared_info->arch
+
+extern unsigned long vcpu_verbose;
+
+long do_iopl(domid_t domain, unsigned int new_io_pl)
+{
+       dummy();
+       return 0;
+}
+
+void schedule_tail(struct domain *next)
+{
+       unsigned long rr7;
+       printk("current=%lx,shared_info=%lx\n",current,current->shared_info);
+       printk("next=%lx,shared_info=%lx\n",next,next->shared_info);
+       if (rr7 = load_region_regs(current)) {
+               printk("schedule_tail: change to rr7 not yet implemented\n");
+       }
+}
+
+extern TR_ENTRY *match_tr(struct domain *d, unsigned long ifa);
+
+void tdpfoo(void) { }
+
+// given a domain virtual address, pte and pagesize, extract the metaphysical
+// address, convert the pte for a physical address for (possibly different)
+// Xen PAGE_SIZE and return modified pte.  (NOTE: TLB insert should use
+// PAGE_SIZE!)
+unsigned long translate_domain_pte(unsigned long pteval,
+       unsigned long address, unsigned long itir)
+{
+       struct domain *d = (struct domain *) current;
+       unsigned long mask, pteval2, mpaddr;
+       unsigned long lookup_domain_mpa(struct domain *,unsigned long);
+       extern struct domain *dom0;
+       extern unsigned long dom0_start, dom0_size;
+
+       // FIXME address had better be pre-validated on insert
+       mask = (1L << ((itir >> 2) & 0x3f)) - 1;
+       mpaddr = ((pteval & _PAGE_PPN_MASK) & ~mask) | (address & mask);
+       if (d == dom0) {
+               if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
+                       //printk("translate_domain_pte: out-of-bounds dom0 mpaddr %p! itc=%lx...\n",mpaddr,ia64_get_itc());
+                       tdpfoo();
+               }
+       }
+       else if ((mpaddr >> PAGE_SHIFT) > d->max_pages) {
+               printf("translate_domain_pte: bad mpa=%p (> %p),vadr=%p,pteval=%p,itir=%p\n",
+                       mpaddr,d->max_pages<<PAGE_SHIFT,address,pteval,itir);
+               tdpfoo();
+       }
+       pteval2 = lookup_domain_mpa(d,mpaddr);
+       pteval2 &= _PAGE_PPN_MASK; // ignore non-addr bits
+       pteval2 |= _PAGE_PL_2; // force PL0->2 (PL3 is unaffected)
+       pteval2 = (pteval & ~_PAGE_PPN_MASK) | pteval2;
+       return pteval2;
+}
+
+// given a current domain metaphysical address, return the physical address
+unsigned long translate_domain_mpaddr(unsigned long mpaddr)
+{
+       extern unsigned long lookup_domain_mpa(struct domain *,unsigned long);
+       unsigned long pteval;
+
+       if (current == dom0) {
+               if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
+                       printk("translate_domain_mpaddr: out-of-bounds dom0 mpaddr %p! continuing...\n",mpaddr);
+                       tdpfoo();
+               }
+       }
+       pteval = lookup_domain_mpa(current,mpaddr);
+       return ((pteval & _PAGE_PPN_MASK) | (mpaddr & ~PAGE_MASK));
+}
+
+void reflect_interruption(unsigned long ifa, unsigned long isr, unsigned long itiriim, struct pt_regs *regs, unsigned long vector)
+{
+       unsigned long vcpu_get_ipsr_int_state(struct domain *,unsigned long);
+       unsigned long vcpu_get_rr_ve(struct domain *,unsigned long);
+       unsigned long vcpu_get_itir_on_fault(struct domain *,unsigned long);
+       struct domain *d = (struct domain *) current;
+
+       if (vector == IA64_EXTINT_VECTOR) {
+               
+               extern unsigned long vcpu_verbose, privop_trace;
+               static first_extint = 1;
+               if (first_extint) {
+                       printf("Delivering first extint to domain: ifa=%p, isr=%p, itir=%p, iip=%p\n",ifa,isr,itiriim,regs->cr_iip);
+                       //privop_trace = 1; vcpu_verbose = 1;
+                       first_extint = 0;
+               }
+       }
+       if (!PSCB(d).interrupt_collection_enabled) {
+               if (!(PSCB(d).ipsr & IA64_PSR_DT)) {
+                       printf("psr.dt off, trying to deliver nested dtlb!\n");
+                       while(1);
+               }
+               vector &= ~0xf;
+               if (vector != IA64_DATA_TLB_VECTOR &&
+                   vector != IA64_DATA_TLB_VECTOR) {
+printf("psr.ic off, delivering fault=%lx,iip=%p,isr=%p,PSCB.iip=%p\n",
+       vector,regs->cr_iip,isr,PSCB(d).iip);
+                       while(1);
+                       
+               }
+//printf("Delivering NESTED DATA TLB fault\n");
+               vector = IA64_DATA_NESTED_TLB_VECTOR;
+               regs->cr_iip = ((unsigned long) PSCB(d).iva + vector) & ~0xffUL;
+               regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET;
+// NOTE: nested trap must NOT pass PSCB address
+               //regs->r31 = (unsigned long) &PSCB(d);
+               return;
+
+       }
+       if ((vector & 0xf) != IA64_FORCED_IFA) PSCB(d).ifa = ifa;
+       else ifa = PSCB(d).ifa;
+       vector &= ~0xf;
+//     always deliver on ALT vector (for now?) because no VHPT
+//     if (!vcpu_get_rr_ve(d,ifa)) {
+               if (vector == IA64_DATA_TLB_VECTOR)
+                       vector = IA64_ALT_DATA_TLB_VECTOR;
+               else if (vector == IA64_INST_TLB_VECTOR)
+                       vector = IA64_ALT_INST_TLB_VECTOR;
+//     }
+       PSCB(d).unat = regs->ar_unat;  // not sure if this is really needed?
+       PSCB(d).precover_ifs = regs->cr_ifs;
+       vcpu_bsw0(d);
+       PSCB(d).ipsr = vcpu_get_ipsr_int_state(d,regs->cr_ipsr);
+       if (vector == IA64_BREAK_VECTOR || vector == IA64_SPECULATION_VECTOR)
+               PSCB(d).iim = itiriim;
+       else PSCB(d).itir = vcpu_get_itir_on_fault(d,ifa);
+       PSCB(d).isr = isr; // this is unnecessary except for interrupts!
+       PSCB(d).iip = regs->cr_iip;
+       PSCB(d).ifs = 0;
+       PSCB(d).incomplete_regframe = 0;
+
+       regs->cr_iip = ((unsigned long) PSCB(d).iva + vector) & ~0xffUL;
+       regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET;
+// FIXME: NEED TO PASS PSCB, BUT **NOT** IN R31 WHICH IS BEING USED FOR ar.pr
+// IN ANY CASE, PASS PINNED ADDRESS, NOT THIS ONE
+       //regs->r31 = (unsigned long) &PSCB(d);
+
+       PSCB(d).interrupt_delivery_enabled = 0;
+       PSCB(d).interrupt_collection_enabled = 0;
+}
+
+void foodpi(void) {}
+
+// ONLY gets called from ia64_leave_kernel
+// ONLY call with interrupts disabled?? (else might miss one?)
+// NEVER successful if already reflecting a trap/fault because psr.i==0
+void deliver_pending_interrupt(struct pt_regs *regs)
+{
+       struct domain *d = (struct domain *) current;
+       // FIXME: Will this work properly if doing an RFI???
+       if (!is_idle_task(d) && user_mode(regs)) {
+               vcpu_poke_timer(d);
+               if (vcpu_deliverable_interrupts(d)) {
+                       unsigned long isr = regs->cr_ipsr & IA64_PSR_RI;
+                       foodpi();
+                       reflect_interruption(0,isr,0,regs,IA64_EXTINT_VECTOR);
+               }
+       }
+}
+
+int handle_lazy_cover(struct domain *d, unsigned long isr, struct pt_regs *regs)
+{
+       if (!PSCB(d).interrupt_collection_enabled) {
+               if (isr & IA64_ISR_IR) {
+//                     printf("Handling lazy cover\n");
+                       PSCB(d).ifs = regs->cr_ifs;
+                       PSCB(d).incomplete_regframe = 1;
+                       regs->cr_ifs = 0;
+                       return(1); // retry same instruction with cr.ifs off
+               }
+       }
+       return(0);
+}
+
+#define IS_XEN_ADDRESS(d,a) ((a >= d->xen_vastart) && (a <= d->xen_vaend))
+
+void xen_handle_domain_access(unsigned long address, unsigned long isr, struct pt_regs *regs, unsigned long itir)
+{
+       struct domain *d = (struct domain *) current;
+       TR_ENTRY *trp;
+       unsigned long psr = regs->cr_ipsr, mask, flags;
+       unsigned long iip = regs->cr_iip;
+       // FIXME should validate address here
+       unsigned long pteval, mpaddr;
+       unsigned long lookup_domain_mpa(struct domain *,unsigned long);
+       IA64FAULT fault;
+       extern void __get_domain_bundle(void);
+
+// NEED TO HANDLE THREE CASES:
+// 1) domain is in metaphysical mode
+// 2) domain address is in TR
+// 3) domain address is not in TR (reflect data miss)
+
+               // got here trying to read a privop bundle
+               //if (d->metaphysical_mode) {
+       if (d->metaphysical_mode && !(address>>61)) {  //FIXME
+               if (d == dom0) {
+                       if (address < dom0_start || address >= dom0_start + dom0_size) {
+                               printk("xen_handle_domain_access: out-of-bounds"
+                                  "dom0 mpaddr %p! continuing...\n",mpaddr);
+                               tdpfoo();
+                       }
+               }
+               pteval = lookup_domain_mpa(d,address);
+               //FIXME: check return value?
+               // would be nice to have a counter here
+               vcpu_itc_no_srlz(d,2,address,pteval,PAGE_SHIFT);
+               return;
+       }
+if (address < 0x4000) printf("WARNING: page_fault @%p, iip=%p\n",address,iip);
+       if (*(unsigned long *)__get_domain_bundle != iip) {
+               printf("Bad user space access @%p ",address);
+               printf("iip=%p, ipsr=%p, b0=%p\n",iip,psr,regs->b0);
+               while(1);
+       }
+               
+       fault = vcpu_tpa(d,address,&mpaddr);
+       if (fault != IA64_NO_FAULT) {
+               // this is hardcoded to handle __get_domain_bundle only
+               regs->r8 = 0; regs->r9 = 0;
+               regs->cr_iip += 0x20;
+               //regs->cr_iip |= (2UL << IA64_PSR_RI_BIT);
+               return;
+       }
+       if (d == dom0) {
+               if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
+                       printk("xen_handle_domain_access: vcpu_tpa returned out-of-bounds dom0 mpaddr %p! continuing...\n",mpaddr);
+                       tdpfoo();
+               }
+       }
+       pteval = lookup_domain_mpa(d,mpaddr);
+       // would be nice to have a counter here
+       //printf("Handling privop data TLB miss\n");
+       // FIXME, must be inlined or potential for nested fault here!
+       vcpu_itc_no_srlz(d,2,address,pteval,PAGE_SHIFT);
+}
+
+void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs, unsigned long itir)
+{
+       struct domain *d = (struct domain *) current;
+       TR_ENTRY *trp;
+       unsigned long psr = regs->cr_ipsr, mask, flags;
+       unsigned long iip = regs->cr_iip;
+       // FIXME should validate address here
+       unsigned long pteval, mpaddr;
+       unsigned long lookup_domain_mpa(struct domain *,unsigned long);
+       unsigned long is_data = !((isr >> IA64_ISR_X_BIT) & 1UL);
+       unsigned long vector;
+       IA64FAULT fault;
+
+
+       //The right way is put in VHPT and take another miss!
+
+       // weak attempt to avoid doing both I/D tlb insert to avoid
+       // problems for privop bundle fetch, doesn't work, deal with later
+       if (IS_XEN_ADDRESS(d,iip) && !IS_XEN_ADDRESS(d,address)) {
+               xen_handle_domain_access(address, isr, regs, itir);
+
+               return;
+       }
+
+       // FIXME: no need to pass itir in to this routine as we need to
+       // compute the virtual itir anyway (based on domain's RR.ps)
+       // AND ACTUALLY reflect_interruption doesn't use it anyway!
+       itir = vcpu_get_itir_on_fault(d,address);
+
+       if (d->metaphysical_mode && (is_data || !(address>>61))) {  //FIXME
+               // FIXME should validate mpaddr here
+               if (d == dom0) {
+                       if (address < dom0_start || address >= dom0_start + dom0_size) {
+                               printk("ia64_do_page_fault: out-of-bounds dom0 mpaddr %p, iip=%p! continuing...\n",address,iip);
+                               printk("ia64_do_page_fault: out-of-bounds dom0 mpaddr %p, old iip=%p!\n",address,d->shared_info->arch.iip);
+                               tdpfoo();
+                       }
+               }
+               pteval = lookup_domain_mpa(d,address);
+               // FIXME, must be inlined or potential for nested fault here!
+               vcpu_itc_no_srlz(d,is_data?2:1,address,pteval,PAGE_SHIFT);
+               return;
+       }
+       if (trp = match_tr(d,address)) {
+               // FIXME address had better be pre-validated on insert
+               pteval = translate_domain_pte(trp->page_flags,address,trp->itir);
+               vcpu_itc_no_srlz(d,is_data?2:1,address,pteval,(trp->itir>>2)&0x3f);
+               return;
+       }
+       vector = is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR;
+       if (handle_lazy_cover(d, isr, regs)) return;
+if (!(address>>61)) { printf("ia64_do_page_fault: @%p???, iip=%p, itc=%p (spinning...)\n",address,iip,ia64_get_itc()); while(1); }
+       if ((isr & IA64_ISR_SP)
+           || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH))
+       {
+               /*
+                * This fault was due to a speculative load or lfetch.fault, set the "ed"
+                * bit in the psr to ensure forward progress.  (Target register will get a
+                * NaT for ld.s, lfetch will be canceled.)
+                */
+               ia64_psr(regs)->ed = 1;
+               return;
+       }
+       reflect_interruption(address, isr, itir, regs, vector);
+}
+
+void
+ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
+           unsigned long iim, unsigned long itir, unsigned long arg5,
+           unsigned long arg6, unsigned long arg7, unsigned long stack)
+{
+       struct pt_regs *regs = (struct pt_regs *) &stack;
+       unsigned long code, error = isr;
+       char buf[128];
+       int result, sig;
+       static const char *reason[] = {
+               "IA-64 Illegal Operation fault",
+               "IA-64 Privileged Operation fault",
+               "IA-64 Privileged Register fault",
+               "IA-64 Reserved Register/Field fault",
+               "Disabled Instruction Set Transition fault",
+               "Unknown fault 5", "Unknown fault 6", "Unknown fault 7", "Illegal Hazard fault",
+               "Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12",
+               "Unknown fault 13", "Unknown fault 14", "Unknown fault 15"
+       };
+#if 0
+printf("ia64_fault, vector=0x%p, ifa=%p, iip=%p, ipsr=%p, isr=%p\n",
+ vector, ifa, regs->cr_iip, regs->cr_ipsr, isr);
+#endif
+
+       if ((isr & IA64_ISR_NA) && ((isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) {
+               /*
+                * This fault was due to lfetch.fault, set "ed" bit in the psr to cancel
+                * the lfetch.
+                */
+               ia64_psr(regs)->ed = 1;
+               printf("ia64_fault: handled lfetch.fault\n");
+               return;
+       }
+
+       switch (vector) {
+             case 24: /* General Exception */
+               code = (isr >> 4) & 0xf;
+               sprintf(buf, "General Exception: %s%s", reason[code],
+                       (code == 3) ? ((isr & (1UL << 37))
+                                      ? " (RSE access)" : " (data access)") : "");
+               if (code == 8) {
+# ifdef CONFIG_IA64_PRINT_HAZARDS
+                       printk("%s[%d]: possible hazard @ ip=%016lx (pr = %016lx)\n",
+                              current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri,
+                              regs->pr);
+# endif
+                       printf("ia64_fault: returning on hazard\n");
+                       return;
+               }
+               break;
+
+             case 25: /* Disabled FP-Register */
+               if (isr & 2) {
+                       //disabled_fph_fault(regs);
+                       //return;
+               }
+               sprintf(buf, "Disabled FPL fault---not supposed to happen!");
+               break;
+
+             case 26: /* NaT Consumption */
+               if (user_mode(regs)) {
+                       void *addr;
+
+                       if (((isr >> 4) & 0xf) == 2) {
+                               /* NaT page consumption */
+                               //sig = SIGSEGV;
+                               //code = SEGV_ACCERR;
+                               addr = (void *) ifa;
+                       } else {
+                               /* register NaT consumption */
+                               //sig = SIGILL;
+                               //code = ILL_ILLOPN;
+                               addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
+                       }
+                       //siginfo.si_signo = sig;
+                       //siginfo.si_code = code;
+                       //siginfo.si_errno = 0;
+                       //siginfo.si_addr = addr;
+                       //siginfo.si_imm = vector;
+                       //siginfo.si_flags = __ISR_VALID;
+                       //siginfo.si_isr = isr;
+                       //force_sig_info(sig, &siginfo, current);
+                       //return;
+               } //else if (ia64_done_with_exception(regs))
+                       //return;
+               sprintf(buf, "NaT consumption");
+               break;
+
+             case 31: /* Unsupported Data Reference */
+               if (user_mode(regs)) {
+                       //siginfo.si_signo = SIGILL;
+                       //siginfo.si_code = ILL_ILLOPN;
+                       //siginfo.si_errno = 0;
+                       //siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
+                       //siginfo.si_imm = vector;
+                       //siginfo.si_flags = __ISR_VALID;
+                       //siginfo.si_isr = isr;
+                       //force_sig_info(SIGILL, &siginfo, current);
+                       //return;
+               }
+               sprintf(buf, "Unsupported data reference");
+               break;
+
+             case 29: /* Debug */
+             case 35: /* Taken Branch Trap */
+             case 36: /* Single Step Trap */
+               //if (fsys_mode(current, regs)) {}
+               switch (vector) {
+                     case 29:
+                       //siginfo.si_code = TRAP_HWBKPT;
+#ifdef CONFIG_ITANIUM
+                       /*
+                        * Erratum 10 (IFA may contain incorrect address) now has
+                        * "NoFix" status.  There are no plans for fixing this.
+                        */
+                       if (ia64_psr(regs)->is == 0)
+                         ifa = regs->cr_iip;
+#endif
+                       break;
+                     case 35: ifa = 0; break;
+                     case 36: ifa = 0; break;
+                     //case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break;
+                     //case 36: siginfo.si_code = TRAP_TRACE; ifa = 0; break;
+               }
+               //siginfo.si_signo = SIGTRAP;
+               //siginfo.si_errno = 0;
+               //siginfo.si_addr  = (void *) ifa;
+               //siginfo.si_imm   = 0;
+               //siginfo.si_flags = __ISR_VALID;
+               //siginfo.si_isr   = isr;
+               //force_sig_info(SIGTRAP, &siginfo, current);
+               //return;
+
+             case 32: /* fp fault */
+             case 33: /* fp trap */
+               //result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr);
+               if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) {
+                       //siginfo.si_signo = SIGFPE;
+                       //siginfo.si_errno = 0;
+                       //siginfo.si_code = FPE_FLTINV;
+                       //siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
+                       //siginfo.si_flags = __ISR_VALID;
+                       //siginfo.si_isr = isr;
+                       //siginfo.si_imm = 0;
+                       //force_sig_info(SIGFPE, &siginfo, current);
+               }
+               //return;
+               sprintf(buf, "FP fault/trap");
+               break;
+
+             case 34:
+               if (isr & 0x2) {
+                       /* Lower-Privilege Transfer Trap */
+                       /*
+                        * Just clear PSR.lp and then return immediately: all the
+                        * interesting work (e.g., signal delivery is done in the kernel
+                        * exit path).
+                        */
+                       //ia64_psr(regs)->lp = 0;
+                       //return;
+                       sprintf(buf, "Lower-Privilege Transfer trap");
+               } else {
+                       /* Unimplemented Instr. Address Trap */
+                       if (user_mode(regs)) {
+                               //siginfo.si_signo = SIGILL;
+                               //siginfo.si_code = ILL_BADIADDR;
+                               //siginfo.si_errno = 0;
+                               //siginfo.si_flags = 0;
+                               //siginfo.si_isr = 0;
+                               //siginfo.si_imm = 0;
+                               //siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
+                               //force_sig_info(SIGILL, &siginfo, current);
+                               //return;
+                       }
+                       sprintf(buf, "Unimplemented Instruction Address fault");
+               }
+               break;
+
+             case 45:
+               printk(KERN_ERR "Unexpected IA-32 exception (Trap 45)\n");
+               printk(KERN_ERR "  iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n",
+                      regs->cr_iip, ifa, isr);
+               //force_sig(SIGSEGV, current);
+               break;
+
+             case 46:
+               printk(KERN_ERR "Unexpected IA-32 intercept trap (Trap 46)\n");
+               printk(KERN_ERR "  iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx, iim - 0x%lx\n",
+                      regs->cr_iip, ifa, isr, iim);
+               //force_sig(SIGSEGV, current);
+               return;
+
+             case 47:
+               sprintf(buf, "IA-32 Interruption Fault (int 0x%lx)", isr >> 16);
+               break;
+
+             default:
+               sprintf(buf, "Fault %lu", vector);
+               break;
+       }
+       //die_if_kernel(buf, regs, error);
+printk("ia64_fault: %s: reflecting\n",buf);
+reflect_interruption(ifa,isr,iim,regs,IA64_GENEX_VECTOR);
+//while(1);
+       //force_sig(SIGILL, current);
+}
+
+unsigned long running_on_sim = 0;
+
+void
+do_ssc(unsigned long ssc, struct pt_regs *regs)
+{
+       extern unsigned long lookup_domain_mpa(struct domain *,unsigned long);
+       unsigned long arg0, arg1, arg2, arg3, retval;
+       char buf[2];
+/**/   static int last_fd, last_count; // FIXME FIXME FIXME
+/**/                                   // BROKEN FOR MULTIPLE DOMAINS & SMP
+/**/   struct ssc_disk_stat { int fd; unsigned count;} *stat, last_stat;
+       extern unsigned long vcpu_verbose, privop_trace;
+
+       arg0 = vcpu_get_gr(current,32);
+       switch(ssc) {
+           case SSC_PUTCHAR:
+               buf[0] = arg0;
+               buf[1] = '\0';
+               printf(buf);
+               break;
+           case SSC_GETCHAR:
+               retval = ia64_ssc(0,0,0,0,ssc);
+               vcpu_set_gr(current,8,retval);
+               break;
+           case SSC_WAIT_COMPLETION:
+               if (arg0) {     // metaphysical address
+
+                       arg0 = translate_domain_mpaddr(arg0);
+/**/                   stat = (struct ssc_disk_stat *)__va(arg0);
+///**/                 if (stat->fd == last_fd) stat->count = last_count;
+/**/                   stat->count = last_count;
+//if (last_count >= PAGE_SIZE) printf("ssc_wait: stat->fd=%d,last_fd=%d,last_count=%d\n",stat->fd,last_fd,last_count);
+///**/                 retval = ia64_ssc(arg0,0,0,0,ssc);
+/**/                   retval = 0;
+               }
+               else retval = -1L;
+               vcpu_set_gr(current,8,retval);
+               break;
+           case SSC_OPEN:
+               arg1 = vcpu_get_gr(current,33); // access rights
+if (!running_on_sim) { printf("SSC_OPEN, not implemented on hardware.  (ignoring...)\n"); arg0 = 0; }
+               if (arg0) {     // metaphysical address
+                       arg0 = translate_domain_mpaddr(arg0);
+                       retval = ia64_ssc(arg0,arg1,0,0,ssc);
+               }
+               else retval = -1L;
+               vcpu_set_gr(current,8,retval);
+               break;
+           case SSC_WRITE:
+           case SSC_READ:
+//if (ssc == SSC_WRITE) printf("DOING AN SSC_WRITE\n");
+               arg1 = vcpu_get_gr(current,33);
+               arg2 = vcpu_get_gr(current,34);
+               arg3 = vcpu_get_gr(current,35);
+               if (arg2) {     // metaphysical address of descriptor
+                       struct ssc_disk_req *req;
+                       unsigned long mpaddr, paddr;
+                       long len;
+
+                       arg2 = translate_domain_mpaddr(arg2);
+                       req = (struct disk_req *)__va(arg2);
+                       req->len &= 0xffffffffL;        // avoid strange bug
+                       len = req->len;
+/**/                   last_fd = arg1;
+/**/                   last_count = len;
+                       mpaddr = req->addr;
+//if (last_count >= PAGE_SIZE) printf("do_ssc: read fd=%d, addr=%p, len=%lx ",last_fd,mpaddr,len);
+                       retval = 0;
+                       if ((mpaddr & PAGE_MASK) != ((mpaddr+len-1) & PAGE_MASK)) {
+                               // do partial page first
+                               req->addr = translate_domain_mpaddr(mpaddr);
+                               req->len = PAGE_SIZE - (req->addr & ~PAGE_MASK);
+                               len -= req->len; mpaddr += req->len;
+                               retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc);
+                               arg3 += req->len; // file offset
+/**/                           last_stat.fd = last_fd;
+/**/                           (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION);
+//if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)[part]=%x ",req->addr,req->len,retval);
+                       }
+                       if (retval >= 0) while (len > 0) {
+                               req->addr = translate_domain_mpaddr(mpaddr);
+                               req->len = (len > PAGE_SIZE) ? PAGE_SIZE : len;
+                               len -= PAGE_SIZE; mpaddr += PAGE_SIZE;
+                               retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc);
+                               arg3 += req->len; // file offset
+// TEMP REMOVED AGAIN                          arg3 += req->len; // file offset
+/**/                           last_stat.fd = last_fd;
+/**/                           (void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION);
+//if (last_count >= PAGE_SIZE) printf("ssc(%p,%lx)=%x ",req->addr,req->len,retval);
+                       }
+                       // set it back to the original value
+                       req->len = last_count;
+               }
+               else retval = -1L;
+               vcpu_set_gr(current,8,retval);
+//if (last_count >= PAGE_SIZE) printf("retval=%x\n",retval);
+               break;
+           case SSC_CONNECT_INTERRUPT:
+               arg1 = vcpu_get_gr(current,33);
+               arg2 = vcpu_get_gr(current,34);
+               arg3 = vcpu_get_gr(current,35);
+               if (!running_on_sim) { printf("SSC_CONNECT_INTERRUPT, not implemented on hardware.  (ignoring...)\n"); break; }
+               (void)ia64_ssc(arg0,arg1,arg2,arg3,ssc);
+               break;
+           case SSC_NETDEV_PROBE:
+               vcpu_set_gr(current,8,-1L);
+               break;
+           default:
+               printf("ia64_handle_break: bad ssc code %lx\n",ssc);
+               break;
+       }
+       vcpu_increment_iip(current);
+}
+
+void fooefi(void) {}
+
+void
+ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim)
+{
+       static int first_time = 1;
+       struct domain *d = (struct domain *) current;
+       extern unsigned long running_on_sim;
+
+       if (first_time) {
+               if (platform_is_hp_ski()) running_on_sim = 1;
+               else running_on_sim = 0;
+               first_time = 0;
+       }
+       if (iim == 0x80001 || iim == 0x80002) { //FIXME: don't hardcode constant
+               if (running_on_sim) do_ssc(vcpu_get_gr(current,36), regs);
+               else do_ssc(vcpu_get_gr(current,36), regs);
+       }
+       else if (iim == d->breakimm) {
+               struct ia64_sal_retval x;
+               switch (regs->r2) {
+                   case FW_HYPERCALL_PAL_CALL:
+                       //printf("*** PAL hypercall: index=%d\n",regs->r28);
+                       //FIXME: This should call a C routine
+                       x = pal_emulator_static(regs->r28);
+                       regs->r8 = x.status; regs->r9 = x.v0;
+                       regs->r10 = x.v1; regs->r11 = x.v2;
+                       break;
+                   case FW_HYPERCALL_SAL_CALL:
+                       x = sal_emulator(vcpu_get_gr(d,32),vcpu_get_gr(d,33),
+                               vcpu_get_gr(d,34),vcpu_get_gr(d,35),
+                               vcpu_get_gr(d,36),vcpu_get_gr(d,37),
+                               vcpu_get_gr(d,38),vcpu_get_gr(d,39));
+                       regs->r8 = x.status; regs->r9 = x.v0;
+                       regs->r10 = x.v1; regs->r11 = x.v2;
+                       break;
+                   case FW_HYPERCALL_EFI_RESET_SYSTEM:
+                       printf("efi.reset_system called ");
+                       if (current == dom0) {
+                               printf("(by dom0)\n ");
+                               (*efi.reset_system)(EFI_RESET_WARM,0,0,NULL);
+                       }
+                       printf("(not supported for non-0 domain)\n");
+                       regs->r8 = EFI_UNSUPPORTED;
+                       break;
+                   case FW_HYPERCALL_EFI_GET_TIME:
+                       {
+                       unsigned long *tv, *tc;
+                       fooefi();
+                       tv = vcpu_get_gr(d,32);
+                       tc = vcpu_get_gr(d,33);
+                       //printf("efi_get_time(%p,%p) called...",tv,tc);
+                       tv = __va(translate_domain_mpaddr(tv));
+                       if (tc) tc = __va(translate_domain_mpaddr(tc));
+                       regs->r8 = (*efi.get_time)(tv,tc);
+                       //printf("and returns %lx\n",regs->r8);
+                       }
+                       break;
+                   case FW_HYPERCALL_EFI_SET_TIME:
+                   case FW_HYPERCALL_EFI_GET_WAKEUP_TIME:
+                   case FW_HYPERCALL_EFI_SET_WAKEUP_TIME:
+                       // FIXME: need fixes in efi.h from 2.6.9
+                   case FW_HYPERCALL_EFI_SET_VIRTUAL_ADDRESS_MAP:
+                       // FIXME: WARNING!! IF THIS EVER GETS IMPLEMENTED
+                       // SOME OF THE OTHER EFI EMULATIONS WILL CHANGE AS 
+                       // POINTER ARGUMENTS WILL BE VIRTUAL!!
+                   case FW_HYPERCALL_EFI_GET_VARIABLE:
+                       // FIXME: need fixes in efi.h from 2.6.9
+                   case FW_HYPERCALL_EFI_GET_NEXT_VARIABLE:
+                   case FW_HYPERCALL_EFI_SET_VARIABLE:
+                   case FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT:
+                       // FIXME: need fixes in efi.h from 2.6.9
+                       regs->r8 = EFI_UNSUPPORTED;
+                       break;
+               }
+               vcpu_increment_iip(current);
+       }
+       else reflect_interruption(ifa,isr,iim,regs,IA64_BREAK_VECTOR);
+}
+
+void
+ia64_handle_privop (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long itir)
+{
+       IA64FAULT vector;
+       struct domain *d = (struct domain *) current;
+       // FIXME: no need to pass itir in to this routine as we need to
+       // compute the virtual itir anyway (based on domain's RR.ps)
+       // AND ACTUALLY reflect_interruption doesn't use it anyway!
+       itir = vcpu_get_itir_on_fault(d,ifa);
+       vector = priv_emulate((struct domain *)current,regs,isr);
+       if (vector == IA64_RETRY) {
+               reflect_interruption(ifa,isr,itir,regs,
+                       IA64_ALT_DATA_TLB_VECTOR | IA64_FORCED_IFA);
+       }
+       else if (vector != IA64_NO_FAULT && vector != IA64_RFI_IN_PROGRESS) {
+               reflect_interruption(ifa,isr,itir,regs,vector);
+       }
+}
+
+#define INTR_TYPE_MAX  10
+UINT64 int_counts[INTR_TYPE_MAX];
+
+void
+ia64_handle_reflection (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim, unsigned long vector)
+{
+       extern unsigned long vcpu_get_itir_on_fault(struct domain *vcpu, UINT64 ifa);
+       struct domain *d = (struct domain *) current;
+       unsigned long check_lazy_cover = 0;
+       unsigned long psr = regs->cr_ipsr;
+       unsigned long itir = vcpu_get_itir_on_fault(d,ifa);
+
+       if (!(psr & IA64_PSR_CPL)) {
+               printf("ia64_handle_reflection: reflecting with priv=0!!\n");
+               while(1);
+       }
+       // FIXME: no need to pass itir in to this routine as we need to
+       // compute the virtual itir anyway (based on domain's RR.ps)
+       // AND ACTUALLY reflect_interruption doesn't use it anyway!
+       itir = vcpu_get_itir_on_fault(d,ifa);
+       switch(vector) {
+           case 8:
+               vector = IA64_DIRTY_BIT_VECTOR; break;
+           case 9:
+               vector = IA64_INST_ACCESS_BIT_VECTOR; break;
+           case 10:
+               check_lazy_cover = 1;
+               vector = IA64_DATA_ACCESS_BIT_VECTOR; break;
+           case 22:
+               vector = IA64_INST_ACCESS_RIGHTS_VECTOR; break;
+           case 23:
+               check_lazy_cover = 1;
+               vector = IA64_DATA_ACCESS_RIGHTS_VECTOR; break;
+           case 25:
+               vector = IA64_DISABLED_FPREG_VECTOR; break;
+           case 26:
+printf("*** NaT fault... attempting to handle as privop\n");
+               vector = priv_emulate(d,regs,isr);
+               if (vector == IA64_NO_FAULT) {
+printf("*** Handled privop masquerading as NaT fault\n");
+                       return;
+               }
+               vector = IA64_NAT_CONSUMPTION_VECTOR; break;
+           case 27:
+//printf("*** Handled speculation vector, itc=%lx!\n",ia64_get_itc());
+               itir = iim;
+               vector = IA64_SPECULATION_VECTOR; break;
+           case 30:
+               // FIXME: Should we handle unaligned refs in Xen??
+               vector = IA64_UNALIGNED_REF_VECTOR; break;
+           default:
+               printf("ia64_handle_reflection: unhandled vector=0x%lx\n",vector);
+               while(vector);
+               return;
+       }
+       if (check_lazy_cover && handle_lazy_cover(d, isr, regs)) return;
+       reflect_interruption(ifa,isr,itir,regs,vector);
+}
diff --git a/xen/arch/ia64/regionreg.c b/xen/arch/ia64/regionreg.c
new file mode 100644 (file)
index 0000000..bb1803a
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * Region register and region id management
+ *
+ * Copyright (C) 2001-2004 Hewlett-Packard Co.
+ *     Dan Magenheimer (dan.magenheimer@hp.com
+ *     Bret Mckee (bret.mckee@hp.com)
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <asm/page.h>
+#include <asm/regionreg.h>
+#include <asm/vhpt.h>
+
+
+#define        IA64_MIN_IMPL_RID_BITS  (IA64_MIN_IMPL_RID_MSB+1)
+#define        IA64_MAX_IMPL_RID_BITS  24
+
+#define MIN_RIDS       (1 << IA64_MIN_IMPL_RID_BITS)
+#define        MIN_RID_MAX     (MIN_RIDS - 1)
+#define        MIN_RID_MASK    (MIN_RIDS - 1)
+#define        MAX_RIDS        (1 << (IA64_MAX_IMPL_RID_BITS))
+#define        MAX_RID         (MAX_RIDS - 1)
+#define        MAX_RID_BLOCKS  (1 << (IA64_MAX_IMPL_RID_BITS-IA64_MIN_IMPL_RID_BITS))
+#define RIDS_PER_RIDBLOCK MIN_RIDS
+
+// This is the one global memory representation of the default Xen region reg
+ia64_rr xen_rr;
+
+#if 0
+// following already defined in include/asm-ia64/gcc_intrin.h
+// it should probably be ifdef'd out from there to ensure all region
+// register usage is encapsulated in this file
+static inline unsigned long
+ia64_get_rr (unsigned long rr)
+{
+           unsigned long r;
+           __asm__ __volatile__ (";;mov %0=rr[%1];;":"=r"(r):"r"(rr):"memory");
+           return r;
+}
+
+static inline void
+ia64_set_rr (unsigned long rr, unsigned long rrv)
+{
+           __asm__ __volatile__ (";;mov rr[%0]=%1;;"::"r"(rr),"r"(rrv):"memory");
+}
+#endif
+
+// use this to allocate a rid out of the "Xen reserved rid block"
+unsigned long allocate_reserved_rid(void)
+{
+       static unsigned long currentrid = XEN_DEFAULT_RID;
+       unsigned long t = currentrid;
+
+       unsigned long max = RIDS_PER_RIDBLOCK;
+
+       if (++currentrid >= max) return(-1UL);
+       return t;
+}
+
+
+// returns -1 if none available
+unsigned long allocate_metaphysical_rid(void)
+{
+       unsigned long rid = allocate_reserved_rid();
+}
+
+int deallocate_metaphysical_rid(unsigned long rid)
+{
+       // fix this when the increment allocation mechanism is fixed.
+       return 1;
+}
+
+
+void init_rr(void)
+{
+       xen_rr.rrval = 0;
+       xen_rr.ve = 0;
+       xen_rr.rid = allocate_reserved_rid();
+       xen_rr.ps = PAGE_SHIFT;
+
+       printf("initialized xen_rr.rid=0x%lx\n", xen_rr.rid);
+}
+
+/*************************************
+  Region Block setup/management
+*************************************/
+
+static int implemented_rid_bits = 0;
+static struct domain *ridblock_owner[MAX_RID_BLOCKS] = { 0 };
+
+void get_impl_rid_bits(void)
+{
+       // FIXME (call PAL)
+//#ifdef CONFIG_MCKINLEY
+       implemented_rid_bits = IA64_MAX_IMPL_RID_BITS;
+//#else
+//#error "rid ranges won't work on Merced"
+//#endif
+       if (implemented_rid_bits <= IA64_MIN_IMPL_RID_BITS ||
+           implemented_rid_bits > IA64_MAX_IMPL_RID_BITS)
+               BUG();
+}
+
+
+/*
+ * Allocate a power-of-two-sized chunk of region id space -- one or more
+ *  "rid blocks"
+ */
+int allocate_rid_range(struct domain *d, unsigned long ridbits)
+{
+       int i, j, n_rid_blocks;
+
+       if (implemented_rid_bits == 0) get_impl_rid_bits();
+       
+       if (ridbits >= IA64_MAX_IMPL_RID_BITS)
+       ridbits = IA64_MAX_IMPL_RID_BITS - 1;
+       
+       if (ridbits < IA64_MIN_IMPL_RID_BITS)
+       ridbits = IA64_MIN_IMPL_RID_BITS;
+
+       // convert to rid_blocks and find one
+       n_rid_blocks = ridbits - IA64_MIN_IMPL_RID_BITS + 1;
+       
+       // skip over block 0, reserved for "meta-physical mappings (and Xen)"
+       for (i = n_rid_blocks; i < MAX_RID_BLOCKS; i += n_rid_blocks) {
+               if (ridblock_owner[i] == NULL) {
+                       for (j = i; j < i + n_rid_blocks; ++j) {
+                               if (ridblock_owner[j]) break;
+                       }
+                       if (ridblock_owner[j] == NULL) break;
+               }
+       }
+       
+       if (i >= MAX_RID_BLOCKS) return 0;
+       
+       // found an unused block:
+       //   (i << min_rid_bits) <= rid < ((i + n) << min_rid_bits)
+       // mark this block as owned
+       for (j = i; j < i + n_rid_blocks; ++j) ridblock_owner[j] = d;
+       
+       // setup domain struct
+       d->rid_bits = ridbits;
+       d->starting_rid = i << IA64_MIN_IMPL_RID_BITS;
+       d->ending_rid = (i+n_rid_blocks) << IA64_MIN_IMPL_RID_BITS;
+       
+       return 1;
+}
+
+
+int deallocate_rid_range(struct domain *d)
+{
+       int i;
+       int rid_block_end = d->ending_rid >> IA64_MIN_IMPL_RID_BITS;
+       int rid_block_start = d->starting_rid >> IA64_MIN_IMPL_RID_BITS;
+
+       return 1;  // KLUDGE ALERT
+       //
+       // not all domains will have allocated RIDs (physical mode loaders for instance)
+       //
+       if (d->rid_bits == 0) return 1;
+
+#ifdef DEBUG
+       for (i = rid_block_start; i < rid_block_end; ++i) {
+               ASSERT(ridblock_owner[i] == d);
+           }
+#endif
+       
+       for (i = rid_block_start; i < rid_block_end; ++i)
+       ridblock_owner[i] = NULL;
+       
+       d->rid_bits = 0;
+       d->starting_rid = 0;
+       d->ending_rid = 0;
+       return 1;
+}
+
+
+// This function is purely for performance... apparently scrambling
+//  bits in the region id makes for better hashing, which means better
+//  use of the VHPT, which means better performance
+// Note that the only time a RID should be mangled is when it is stored in
+//  a region register; anytime it is "viewable" outside of this module,
+//  it should be unmangled
+
+//This appears to work in Xen... turn it on later so no complications yet
+//#define CONFIG_MANGLE_RIDS
+#ifdef CONFIG_MANGLE_RIDS
+static inline unsigned long
+vmMangleRID(unsigned long RIDVal)
+{
+       union bits64 { unsigned char bytes[4]; unsigned long uint; };
+
+       union bits64 t;
+       unsigned char tmp;
+
+       t.uint = RIDVal;
+       tmp = t.bytes[1];
+       t.bytes[1] = t.bytes[3];
+       t.bytes[3] = tmp;
+
+       return t.uint;
+}
+
+// since vmMangleRID is symmetric, use it for unmangling also
+#define vmUnmangleRID(x)       vmMangleRID(x)
+#else
+// no mangling/unmangling
+#define vmMangleRID(x) (x)
+#define vmUnmangleRID(x) (x)
+#endif
+
+static inline void
+set_rr_no_srlz(unsigned long rr, unsigned long rrval)
+{
+       ia64_set_rr(rr, vmMangleRID(rrval));
+}
+
+void
+set_rr(unsigned long rr, unsigned long rrval)
+{
+       ia64_set_rr(rr, vmMangleRID(rrval));
+       ia64_srlz_d();
+}
+
+unsigned long
+get_rr(unsigned long rr)
+{
+       return vmUnmangleRID(ia64_get_rr(rr));
+}
+
+static inline int validate_page_size(unsigned long ps)
+{
+       switch(ps) {
+           case 12: case 13: case 14: case 16: case 18:
+           case 20: case 22: case 24: case 26: case 28:
+               return 1;
+           default:
+               return 0;
+       }
+}
+
+// validates and changes a single region register
+// in the currently executing domain
+// Passing a value of -1 is a (successful) no-op
+// NOTE: DOES NOT SET VCPU's rrs[x] value!!
+int set_one_rr(unsigned long rr, unsigned long val)
+{
+       struct domain *d = current;
+       unsigned long rreg = REGION_NUMBER(rr);
+       ia64_rr rrv, newrrv, memrrv;
+       unsigned long newrid;
+
+       if (val == -1) return 1;
+
+       rrv.rrval = val;
+       newrrv.rrval = 0;
+       newrid = d->starting_rid + rrv.rid;
+
+       if (newrid > d->ending_rid) return 0;
+
+       memrrv.rrval = rrv.rrval;
+       if (rreg == 7) {
+               newrrv.rid = newrid;
+               newrrv.ve = VHPT_ENABLED_REGION_7;
+               newrrv.ps = IA64_GRANULE_SHIFT;
+               ia64_new_rr7(vmMangleRID(newrrv.rrval));
+       }
+       else {
+               newrrv.rid = newrid;
+               // FIXME? region 6 needs to be uncached for EFI to work
+               if (rreg == 6) newrrv.ve = VHPT_ENABLED_REGION_7;
+               else newrrv.ve = VHPT_ENABLED_REGION_0_TO_6;
+               newrrv.ps = PAGE_SHIFT;
+               set_rr(rr,newrrv.rrval);
+       }
+       return 1;
+}
+
+// set rr0 to the passed rid (for metaphysical mode so don't use domain offset
+int set_metaphysical_rr(unsigned long rr, unsigned long rid)
+{
+       ia64_rr rrv;
+       
+       rrv.rrval = 0;
+       rrv.rid = rid;
+       rrv.ps = PAGE_SHIFT;
+//     rrv.ve = 1;     FIXME: TURN ME BACK ON WHEN VHPT IS WORKING
+       rrv.ve = 0;
+       set_rr(rr,rrv.rrval);
+}
+
+// validates/changes region registers 0-6 in the currently executing domain
+// Note that this is the one and only SP API (other than executing a privop)
+// for a domain to use to change region registers
+int set_all_rr( u64 rr0, u64 rr1, u64 rr2, u64 rr3,
+                    u64 rr4, u64 rr5, u64 rr6, u64 rr7)
+{
+       if (!set_one_rr(0x0000000000000000L, rr0)) return 0;
+       if (!set_one_rr(0x2000000000000000L, rr1)) return 0;
+       if (!set_one_rr(0x4000000000000000L, rr2)) return 0;
+       if (!set_one_rr(0x6000000000000000L, rr3)) return 0;
+       if (!set_one_rr(0x8000000000000000L, rr4)) return 0;
+       if (!set_one_rr(0xa000000000000000L, rr5)) return 0;
+       if (!set_one_rr(0xc000000000000000L, rr6)) return 0;
+       if (!set_one_rr(0xe000000000000000L, rr7)) return 0;
+       return 1;
+}
+
+void init_all_rr(struct domain *d)
+{
+       ia64_rr rrv;
+
+       rrv.rrval = 0;
+       rrv.rid = d->metaphysical_rid;
+       rrv.ps = PAGE_SHIFT;
+       rrv.ve = 1;
+       d->shared_info->arch.rrs[0] = -1;
+       d->shared_info->arch.rrs[1] = rrv.rrval;
+       d->shared_info->arch.rrs[2] = rrv.rrval;
+       d->shared_info->arch.rrs[3] = rrv.rrval;
+       d->shared_info->arch.rrs[4] = rrv.rrval;
+       d->shared_info->arch.rrs[5] = rrv.rrval;
+       d->shared_info->arch.rrs[6] = rrv.rrval;
+//     d->shared_info->arch.rrs[7] = rrv.rrval;
+}
+
+
+/* XEN/ia64 INTERNAL ROUTINES */
+
+unsigned long physicalize_rid(struct domain *d, unsigned long rid)
+{
+       ia64_rr rrv;
+           
+       rrv.rrval = rid;
+       rrv.rid += d->starting_rid;
+       return rrv.rrval;
+}
+
+unsigned long
+virtualize_rid(struct domain *d, unsigned long rid)
+{
+       ia64_rr rrv;
+           
+       rrv.rrval = rid;
+       rrv.rid -= d->starting_rid;
+       return rrv.rrval;
+}
+
+// loads a thread's region register (0-6) state into
+// the real physical region registers.  Returns the
+// (possibly mangled) bits to store into rr7
+// iff it is different than what is currently in physical
+// rr7 (because we have to to assembly and physical mode
+// to change rr7).  If no change to rr7 is required, returns 0.
+//
+unsigned long load_region_regs(struct domain *d)
+{
+       unsigned long rr0, rr1,rr2, rr3, rr4, rr5, rr6;
+       unsigned long oldrr7, newrr7;
+       // TODO: These probably should be validated
+
+       if (d->metaphysical_mode) {
+               ia64_rr rrv;
+
+               rrv.rid = d->metaphysical_rid;
+               rrv.ps = PAGE_SHIFT;
+               rrv.ve = 1;
+               rr0 = rr1 = rr2 = rr3 = rr4 = rr5 = rr6 = newrr7 = rrv.rrval;
+       }
+       else {
+               rr0 = physicalize_rid(d, d->shared_info->arch.rrs[0]);
+               rr1 = physicalize_rid(d, d->shared_info->arch.rrs[1]);
+               rr2 = physicalize_rid(d, d->shared_info->arch.rrs[2]);
+               rr3 = physicalize_rid(d, d->shared_info->arch.rrs[3]);
+               rr4 = physicalize_rid(d, d->shared_info->arch.rrs[4]);
+               rr5 = physicalize_rid(d, d->shared_info->arch.rrs[5]);
+               rr6 = physicalize_rid(d, d->shared_info->arch.rrs[6]);
+               newrr7 = physicalize_rid(d, d->shared_info->arch.rrs[7]);
+       }
+
+       set_rr_no_srlz(0x0000000000000000L, rr0);
+       set_rr_no_srlz(0x2000000000000000L, rr1);
+       set_rr_no_srlz(0x4000000000000000L, rr2);
+       set_rr_no_srlz(0x6000000000000000L, rr3);
+       set_rr_no_srlz(0x8000000000000000L, rr4);
+       set_rr_no_srlz(0xa000000000000000L, rr5);
+       set_rr_no_srlz(0xc000000000000000L, rr6);
+       ia64_srlz_d();
+       oldrr7 = get_rr(0xe000000000000000L);
+       if (oldrr7 != newrr7) {
+               newrr7 = (newrr7 & ~0xff) | (PAGE_SHIFT << 2) | 1;
+               return vmMangleRID(newrr7);
+       }
+       else return 0;
+}
diff --git a/xen/arch/ia64/vcpu.c b/xen/arch/ia64/vcpu.c
new file mode 100644 (file)
index 0000000..d0d6277
--- /dev/null
@@ -0,0 +1,1559 @@
+/*
+ * Virtualized CPU functions
+ * 
+ * Copyright (C) 2004 Hewlett-Packard Co.
+ *     Dan Magenheimer (dan.magenheimer@hp.com)
+ *
+ */
+
+#include <linux/sched.h>
+#include <asm/ia64_int.h>
+#include <asm/vcpu.h>
+#include <asm/regionreg.h>
+#include <asm/tlb.h>
+#include <asm/processor.h>
+#include <asm/delay.h>
+
+typedef        union {
+       struct ia64_psr;
+       unsigned long i64;
+} PSR;
+
+//typedef      struct pt_regs  REGS;
+//typedef struct domain VCPU;
+
+// this def for vcpu_regs won't work if kernel stack is present
+#define        vcpu_regs(vcpu) ((struct pt_regs *) vcpu->regs)
+#define        PSCB(x) x->shared_info->arch
+
+#define        TRUE    1
+#define        FALSE   0
+#define        IA64_PTA_SZ_BIT         2
+#define        IA64_PTA_VF_BIT         8
+#define        IA64_PTA_BASE_BIT       15
+#define        IA64_PTA_LFMT           (1UL << IA64_PTA_VF_BIT)
+#define        IA64_PTA_SZ(x)  (x##UL << IA64_PTA_SZ_BIT)
+
+#define STATIC
+
+unsigned long vcpu_verbose = 0;
+#define verbose(a...) do {if (vcpu_verbose) printf(a);} while(0)
+
+/**************************************************************************
+ VCPU general register access routines
+**************************************************************************/
+
+UINT64
+vcpu_get_gr(VCPU *vcpu, unsigned reg)
+{
+       REGS *regs = vcpu_regs(vcpu);
+       UINT64 val;
+
+       if (!reg) return 0;
+       getreg(reg,&val,0,regs);        // FIXME: handle NATs later
+       return val;
+}
+
+// returns:
+//   IA64_ILLOP_FAULT if the register would cause an Illegal Operation fault
+//   IA64_NO_FAULT otherwise
+IA64FAULT
+vcpu_set_gr(VCPU *vcpu, unsigned reg, UINT64 value)
+{
+       REGS *regs = vcpu_regs(vcpu);
+       long sof = (regs->cr_ifs) & 0x7f;
+
+       if (!reg) return IA64_ILLOP_FAULT;
+       if (reg >= sof + 32) return IA64_ILLOP_FAULT;
+       setreg(reg,value,0,regs);       // FIXME: handle NATs later
+       return IA64_NO_FAULT;
+}
+
+/**************************************************************************
+ VCPU privileged application register access routines
+**************************************************************************/
+
+IA64FAULT vcpu_set_ar(VCPU *vcpu, UINT64 reg, UINT64 val)
+{
+       if (reg == 44) return (vcpu_set_itc(vcpu,val));
+       if (reg == 27) return (IA64_ILLOP_FAULT);
+       if (reg > 7) return (IA64_ILLOP_FAULT);
+       PSCB(vcpu).krs[reg] = val;
+#if 0
+// for now, privify kr read's so all kr accesses are privileged
+       switch (reg) {
+             case 0: asm volatile ("mov ar.k0=%0" :: "r"(val)); break;
+             case 1: asm volatile ("mov ar.k1=%0" :: "r"(val)); break;
+             case 2: asm volatile ("mov ar.k2=%0" :: "r"(val)); break;
+             case 3: asm volatile ("mov ar.k3=%0" :: "r"(val)); break;
+             case 4: asm volatile ("mov ar.k4=%0" :: "r"(val)); break;
+             case 5: asm volatile ("mov ar.k5=%0" :: "r"(val)); break;
+             case 6: asm volatile ("mov ar.k6=%0" :: "r"(val)); break;
+             case 7: asm volatile ("mov ar.k7=%0" :: "r"(val)); break;
+             case 27: asm volatile ("mov ar.cflg=%0" :: "r"(val)); break;
+       }
+#endif
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_get_ar(VCPU *vcpu, UINT64 reg, UINT64 *val)
+{
+       if (reg > 7) return (IA64_ILLOP_FAULT);
+       *val = PSCB(vcpu).krs[reg];
+       return IA64_NO_FAULT;
+}
+
+/**************************************************************************
+ VCPU processor status register access routines
+**************************************************************************/
+
+void vcpu_set_metaphysical_mode(VCPU *vcpu, BOOLEAN newmode)
+{
+       /* only do something if mode changes */
+       if (!!newmode ^ !!vcpu->metaphysical_mode) {
+               if (newmode) set_metaphysical_rr(0,vcpu->metaphysical_rid);
+               else if (PSCB(vcpu).rrs[0] != -1)
+                       set_one_rr(0, PSCB(vcpu).rrs[0]);
+               vcpu->metaphysical_mode = newmode;
+       }
+}
+
+IA64FAULT vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24)
+{
+       struct ia64_psr psr, imm, *ipsr;
+       REGS *regs = vcpu_regs(vcpu);
+
+       // TODO: All of these bits need to be virtualized
+       // TODO: Only allowed for current vcpu
+       __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory");
+       ipsr = (struct ia64_psr *)&regs->cr_ipsr;
+       imm = *(struct ia64_psr *)&imm24;
+       // interrupt flag
+       if (imm.i) PSCB(vcpu).interrupt_delivery_enabled = 0;
+       if (imm.ic)  PSCB(vcpu).interrupt_collection_enabled = 0;
+       // interrupt collection flag
+       //if (imm.ic) PSCB(vcpu).interrupt_delivery_enabled = 0;
+       // just handle psr.up and psr.pp for now
+       if (imm24 & ~(IA64_PSR_PP | IA64_PSR_UP | IA64_PSR_SP
+               | IA64_PSR_I | IA64_PSR_IC | IA64_PSR_DT
+               | IA64_PSR_DFL | IA64_PSR_DFH))
+                       return (IA64_ILLOP_FAULT);
+       if (imm.dfh) ipsr->dfh = 0;
+       if (imm.dfl) ipsr->dfl = 0;
+       if (imm.pp) { ipsr->pp = 0; psr.pp = 0; }
+       if (imm.up) { ipsr->up = 0; psr.up = 0; }
+       if (imm.sp) { ipsr->sp = 0; psr.sp = 0; }
+       if (imm.dt) vcpu_set_metaphysical_mode(vcpu,TRUE);
+       __asm__ __volatile (";; mov psr.l=%0;; srlz.d"::"r"(psr):"memory");
+       return IA64_NO_FAULT;
+}
+
+extern UINT64 vcpu_check_pending_interrupts(VCPU *vcpu);
+#define SPURIOUS_VECTOR 0xf
+
+IA64FAULT vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24)
+{
+       struct ia64_psr psr, imm, *ipsr;
+       REGS *regs = vcpu_regs(vcpu);
+       UINT64 mask, enabling_interrupts = 0;
+
+       // TODO: All of these bits need to be virtualized
+       __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory");
+       imm = *(struct ia64_psr *)&imm24;
+       ipsr = (struct ia64_psr *)&regs->cr_ipsr;
+       // just handle psr.sp,pp and psr.i,ic (and user mask) for now
+       mask = IA64_PSR_PP|IA64_PSR_SP|IA64_PSR_I|IA64_PSR_IC|IA64_PSR_UM |
+               IA64_PSR_DT|IA64_PSR_DFL|IA64_PSR_DFH;
+       if (imm24 & ~mask) return (IA64_ILLOP_FAULT);
+       if (imm.dfh) ipsr->dfh = 1;
+       if (imm.dfl) ipsr->dfl = 1;
+       if (imm.pp) { ipsr->pp = 1; psr.pp = 1; }
+       if (imm.sp) { ipsr->sp = 1; psr.sp = 1; }
+       if (imm.i) {
+               if (!PSCB(vcpu).interrupt_delivery_enabled) {
+//printf("vcpu_set_psr_sm: psr.ic 0->1 ");
+                       enabling_interrupts = 1;
+               }
+               PSCB(vcpu).interrupt_delivery_enabled = 1;
+       }
+       if (imm.ic)  PSCB(vcpu).interrupt_collection_enabled = 1;
+       // TODO: do this faster
+       if (imm.mfl) { ipsr->mfl = 1; psr.mfl = 1; }
+       if (imm.ac) { ipsr->ac = 1; psr.ac = 1; }
+       if (imm.up) { ipsr->up = 1; psr.up = 1; }
+       if (imm.be) {
+               printf("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n");
+               return (IA64_ILLOP_FAULT);
+       }
+       if (imm.dt) vcpu_set_metaphysical_mode(vcpu,FALSE);
+       __asm__ __volatile (";; mov psr.l=%0;; srlz.d"::"r"(psr):"memory");
+#if 0 // now done with deliver_pending_interrupts
+       if (enabling_interrupts) {
+               if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) {
+//printf("with interrupts pending\n");
+                       return IA64_EXTINT_VECTOR;
+               }
+//else printf("but nothing pending\n");
+       }
+#endif
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_psr_l(VCPU *vcpu, UINT64 val)
+{
+       struct ia64_psr psr, newpsr, *ipsr;
+       REGS *regs = vcpu_regs(vcpu);
+       UINT64 enabling_interrupts = 0;
+
+       // TODO: All of these bits need to be virtualized
+       __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory");
+       newpsr = *(struct ia64_psr *)&val;
+       ipsr = (struct ia64_psr *)&regs->cr_ipsr;
+       // just handle psr.up and psr.pp for now
+       //if (val & ~(IA64_PSR_PP | IA64_PSR_UP | IA64_PSR_SP)) return (IA64_ILLOP_FAULT);
+       // however trying to set other bits can't be an error as it is in ssm
+       if (newpsr.dfh) ipsr->dfh = 1;
+       if (newpsr.dfl) ipsr->dfl = 1;
+       if (newpsr.pp) { ipsr->pp = 1; psr.pp = 1; }
+       if (newpsr.up) { ipsr->up = 1; psr.up = 1; }
+       if (newpsr.sp) { ipsr->sp = 1; psr.sp = 1; }
+       if (newpsr.i) {
+               if (!PSCB(vcpu).interrupt_delivery_enabled)
+                       enabling_interrupts = 1;
+               PSCB(vcpu).interrupt_delivery_enabled = 1;
+       }
+       if (newpsr.ic)  PSCB(vcpu).interrupt_collection_enabled = 1;
+       if (newpsr.mfl) { ipsr->mfl = 1; psr.mfl = 1; }
+       if (newpsr.ac) { ipsr->ac = 1; psr.ac = 1; }
+       if (newpsr.up) { ipsr->up = 1; psr.up = 1; }
+       if (newpsr.dt && newpsr.rt) vcpu_set_metaphysical_mode(vcpu,FALSE);
+       else vcpu_set_metaphysical_mode(vcpu,TRUE);
+       if (newpsr.be) {
+               printf("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n");
+               return (IA64_ILLOP_FAULT);
+       }
+       //__asm__ __volatile (";; mov psr.l=%0;; srlz.d"::"r"(psr):"memory");
+#if 0 // now done with deliver_pending_interrupts
+       if (enabling_interrupts) {
+               if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR)
+                       return IA64_EXTINT_VECTOR;
+       }
+#endif
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_get_psr(VCPU *vcpu, UINT64 *pval)
+{
+       UINT64 psr;
+       struct ia64_psr newpsr;
+
+       // TODO: This needs to return a "filtered" view of
+       // the psr, not the actual psr.  Probably the psr needs
+       // to be a field in regs (in addition to ipsr).
+       __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory");
+       newpsr = *(struct ia64_psr *)&psr;
+       if (newpsr.cpl == 2) newpsr.cpl = 0;
+       if (PSCB(vcpu).interrupt_delivery_enabled) newpsr.i = 1;
+       else newpsr.i = 0;
+       if (PSCB(vcpu).interrupt_collection_enabled) newpsr.ic = 1;
+       else newpsr.ic = 0;
+       *pval = *(unsigned long *)&newpsr;
+       return IA64_NO_FAULT;
+}
+
+BOOLEAN vcpu_get_psr_ic(VCPU *vcpu)
+{
+       return !!PSCB(vcpu).interrupt_collection_enabled;
+}
+
+BOOLEAN vcpu_get_psr_i(VCPU *vcpu)
+{
+       return !!PSCB(vcpu).interrupt_delivery_enabled;
+}
+
+UINT64 vcpu_get_ipsr_int_state(VCPU *vcpu,UINT64 prevpsr)
+{
+       UINT64 dcr = PSCB(vcpu).dcr;
+       PSR psr = {0};
+       
+       //printf("*** vcpu_get_ipsr_int_state (0x%016lx)...",prevpsr);
+       psr.i64 = prevpsr;
+       psr.be = 0; if (dcr & IA64_DCR_BE) psr.be = 1;
+       psr.pp = 0; if (dcr & IA64_DCR_PP) psr.pp = 1;
+       psr.ic = PSCB(vcpu).interrupt_collection_enabled;
+       psr.i = PSCB(vcpu).interrupt_delivery_enabled;
+       psr.bn = PSCB(vcpu).banknum;
+       psr.dt = 1; psr.it = 1; psr.rt = 1;
+       if (psr.cpl == 2) psr.cpl = 0; // !!!! fool domain
+       // psr.pk = 1;
+       //printf("returns 0x%016lx...",psr.i64);
+       return psr.i64;
+}
+
+/**************************************************************************
+ VCPU control register access routines
+**************************************************************************/
+
+IA64FAULT vcpu_get_dcr(VCPU *vcpu, UINT64 *pval)
+{
+extern unsigned long privop_trace;
+//privop_trace=0;
+//verbose("vcpu_get_dcr: called @%p\n",PSCB(vcpu).iip);
+       // Reads of cr.dcr on Xen always have the sign bit set, so
+       // a domain can differentiate whether it is running on SP or not
+       *pval = PSCB(vcpu).dcr | 0x8000000000000000L;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_iva(VCPU *vcpu, UINT64 *pval)
+{
+       *pval = PSCB(vcpu).iva & ~0x7fffL;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_pta(VCPU *vcpu, UINT64 *pval)
+{
+       *pval = PSCB(vcpu).pta;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_ipsr(VCPU *vcpu, UINT64 *pval)
+{
+       //REGS *regs = vcpu_regs(vcpu);
+       //*pval = regs->cr_ipsr;
+       *pval = PSCB(vcpu).ipsr;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_isr(VCPU *vcpu, UINT64 *pval)
+{
+       *pval = PSCB(vcpu).isr;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_iip(VCPU *vcpu, UINT64 *pval)
+{
+       //REGS *regs = vcpu_regs(vcpu);
+       //*pval = regs->cr_iip;
+       *pval = PSCB(vcpu).iip;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_ifa(VCPU *vcpu, UINT64 *pval)
+{
+       UINT64 val = PSCB(vcpu).ifa;
+       *pval = val;
+       return (IA64_NO_FAULT);
+}
+
+
+unsigned long vcpu_get_itir_on_fault(VCPU *vcpu, UINT64 ifa)
+{
+       ia64_rr rr;
+
+       rr.rrval = 0;
+       rr.ps = vcpu_get_rr_ps(vcpu,ifa);
+       rr.rid = vcpu_get_rr_rid(vcpu,ifa);
+       return (rr.rrval);
+}
+
+
+IA64FAULT vcpu_get_itir(VCPU *vcpu, UINT64 *pval)
+{
+       UINT64 val = PSCB(vcpu).itir;
+       *pval = val;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_iipa(VCPU *vcpu, UINT64 *pval)
+{
+       UINT64 val = PSCB(vcpu).iipa;
+       // SP entry code does not save iipa yet nor does it get
+       //  properly delivered in the pscb
+       printf("*** vcpu_get_iipa: cr.iipa not fully implemented yet!!\n");
+       *pval = val;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_ifs(VCPU *vcpu, UINT64 *pval)
+{
+       //PSCB(vcpu).ifs = PSCB(vcpu)->regs.cr_ifs;
+       //*pval = PSCB(vcpu).regs.cr_ifs;
+       *pval = PSCB(vcpu).ifs;
+       PSCB(vcpu).incomplete_regframe = 0;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_iim(VCPU *vcpu, UINT64 *pval)
+{
+       UINT64 val = PSCB(vcpu).iim;
+       *pval = val;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_iha(VCPU *vcpu, UINT64 *pval)
+{
+       return vcpu_thash(vcpu,PSCB(vcpu).ifa,pval);
+}
+
+IA64FAULT vcpu_set_dcr(VCPU *vcpu, UINT64 val)
+{
+extern unsigned long privop_trace;
+//privop_trace=1;
+       // Reads of cr.dcr on SP always have the sign bit set, so
+       // a domain can differentiate whether it is running on SP or not
+       // Thus, writes of DCR should ignore the sign bit
+//verbose("vcpu_set_dcr: called\n");
+       PSCB(vcpu).dcr = val & ~0x8000000000000000L;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_iva(VCPU *vcpu, UINT64 val)
+{
+       PSCB(vcpu).iva = val & ~0x7fffL;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_pta(VCPU *vcpu, UINT64 val)
+{
+       if (val & IA64_PTA_LFMT) {
+               printf("*** No support for VHPT long format yet!!\n");
+               return (IA64_ILLOP_FAULT);
+       }
+       if (val & (0x3f<<9)) /* reserved fields */ return IA64_RSVDREG_FAULT;
+       if (val & 2) /* reserved fields */ return IA64_RSVDREG_FAULT;
+       PSCB(vcpu).pta = val;
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_ipsr(VCPU *vcpu, UINT64 val)
+{
+       PSCB(vcpu).ipsr = val;
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_isr(VCPU *vcpu, UINT64 val)
+{
+       PSCB(vcpu).isr = val;
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_iip(VCPU *vcpu, UINT64 val)
+{
+       PSCB(vcpu).iip = val;
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_increment_iip(VCPU *vcpu)
+{
+       REGS *regs = vcpu_regs(vcpu);
+       struct ia64_psr *ipsr = (struct ia64_psr *)&regs->cr_ipsr;
+       if (ipsr->ri == 2) { ipsr->ri=0; regs->cr_iip += 16; }
+       else ipsr->ri++;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_ifa(VCPU *vcpu, UINT64 val)
+{
+       PSCB(vcpu).ifa = val;
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_itir(VCPU *vcpu, UINT64 val)
+{
+       PSCB(vcpu).itir = val;
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_iipa(VCPU *vcpu, UINT64 val)
+{
+       // SP entry code does not save iipa yet nor does it get
+       //  properly delivered in the pscb
+       printf("*** vcpu_set_iipa: cr.iipa not fully implemented yet!!\n");
+       PSCB(vcpu).iipa = val;
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_ifs(VCPU *vcpu, UINT64 val)
+{
+       //REGS *regs = vcpu_regs(vcpu);
+       PSCB(vcpu).ifs = val;
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_iim(VCPU *vcpu, UINT64 val)
+{
+       PSCB(vcpu).iim = val;
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_set_iha(VCPU *vcpu, UINT64 val)
+{
+       PSCB(vcpu).iha = val;
+       return IA64_NO_FAULT;
+}
+
+/**************************************************************************
+ VCPU interrupt control register access routines
+**************************************************************************/
+
+void vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector)
+{
+       if (vector & ~0xff) {
+               printf("vcpu_pend_interrupt: bad vector\n");
+               return;
+       }
+       if (!test_bit(vector,PSCB(vcpu).delivery_mask)) return;
+       if (test_bit(vector,PSCB(vcpu).irr)) {
+//printf("vcpu_pend_interrupt: overrun\n");
+       }
+       set_bit(vector,PSCB(vcpu).irr);
+}
+
+#define        IA64_TPR_MMI    0x10000
+#define        IA64_TPR_MIC    0x000f0
+
+/* checks to see if a VCPU has any unmasked pending interrupts
+ * if so, returns the highest, else returns SPURIOUS_VECTOR */
+/* NOTE: Since this gets called from vcpu_get_ivr() and the
+ * semantics of "mov rx=cr.ivr" ignore the setting of the psr.i bit,
+ * this routine also ignores pscb.interrupt_delivery_enabled
+ * and this must be checked independently; see vcpu_deliverable interrupts() */
+UINT64 vcpu_check_pending_interrupts(VCPU *vcpu)
+{
+       UINT64 *p, *q, *r, bits, bitnum, mask, i, vector;
+
+       p = &PSCB(vcpu).irr[3];
+       q = &PSCB(vcpu).delivery_mask[3];
+       r = &PSCB(vcpu).insvc[3];
+       for (i = 3; ; p--, q--, r--, i--) {
+               bits = *p & *q;
+               if (bits) break; // got a potential interrupt
+               if (*r) {
+                       // nothing in this word which is pending+inservice
+                       // but there is one inservice which masks lower
+                       return SPURIOUS_VECTOR;
+               }
+               if (i == 0) {
+               // checked all bits... nothing pending+inservice
+                       return SPURIOUS_VECTOR;
+               }
+       }
+       // have a pending,deliverable interrupt... see if it is masked
+       bitnum = ia64_fls(bits);
+//printf("XXXXXXX vcpu_check_pending_interrupts: got bitnum=%p...",bitnum);
+       vector = bitnum+(i*64);
+       mask = 1L << bitnum;
+//printf("XXXXXXX vcpu_check_pending_interrupts: got vector=%p...",vector);
+       if (*r >= mask) {
+               // masked by equal inservice
+//printf("but masked by equal inservice\n");
+               return SPURIOUS_VECTOR;
+       }
+       if (PSCB(vcpu).tpr & IA64_TPR_MMI) {
+               // tpr.mmi is set
+//printf("but masked by tpr.mmi\n");
+               return SPURIOUS_VECTOR;
+       }
+       if (((PSCB(vcpu).tpr & IA64_TPR_MIC) + 15) >= vector) {
+               //tpr.mic masks class
+//printf("but masked by tpr.mic\n");
+               return SPURIOUS_VECTOR;
+       }
+
+//printf("returned to caller\n");
+       return vector;
+}
+
+UINT64 vcpu_deliverable_interrupts(VCPU *vcpu)
+{
+       return (vcpu_get_psr_i(vcpu) &&
+               vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR);
+}
+
+IA64FAULT vcpu_get_lid(VCPU *vcpu, UINT64 *pval)
+{
+extern unsigned long privop_trace;
+//privop_trace=1;
+       //TODO: Implement this
+       printf("vcpu_get_lid: WARNING: Getting cr.lid always returns zero\n");
+       *pval = 0;
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_get_ivr(VCPU *vcpu, UINT64 *pval)
+{
+       int i;
+       UINT64 vector, mask;
+#if 1
+       static char firstivr = 1;
+       static char firsttime[256];
+       if (firstivr) {
+               int i;
+               for (i=0;i<256;i++) firsttime[i]=1;
+               firstivr=0;
+       }
+#endif
+
+       vector = vcpu_check_pending_interrupts(vcpu);
+       if (vector == SPURIOUS_VECTOR) {
+               PSCB(vcpu).pending_interruption = 0;
+               *pval = vector;
+               return IA64_NO_FAULT;
+       }
+       // now have an unmasked, pending, deliverable vector!
+       // getting ivr has "side effects"
+#if 0
+       if (firsttime[vector]) {
+               printf("*** First get_ivr on vector=%d,itc=%lx\n",
+                       vector,ia64_get_itc());
+               firsttime[vector]=0;
+       }
+#endif
+       i = vector >> 6;
+       mask = 1L << (vector & 0x3f);
+//printf("ZZZZZZ vcpu_get_ivr: setting insvc mask for vector %ld\n",vector);
+       PSCB(vcpu).insvc[i] |= mask;
+       PSCB(vcpu).irr[i] &= ~mask;
+       PSCB(vcpu).pending_interruption--;
+       *pval = vector;
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_get_tpr(VCPU *vcpu, UINT64 *pval)
+{
+       *pval = PSCB(vcpu).tpr;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_eoi(VCPU *vcpu, UINT64 *pval)
+{
+       *pval = 0L;  // reads of eoi always return 0
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_irr0(VCPU *vcpu, UINT64 *pval)
+{
+#ifndef IRR_USE_FIXED
+       printk("vcpu_get_irr: called, not implemented yet\n");
+       return IA64_ILLOP_FAULT;
+#else
+       *pval = vcpu->irr[0];
+       return (IA64_NO_FAULT);
+#endif
+}
+
+IA64FAULT vcpu_get_irr1(VCPU *vcpu, UINT64 *pval)
+{
+#ifndef IRR_USE_FIXED
+       printk("vcpu_get_irr: called, not implemented yet\n");
+       return IA64_ILLOP_FAULT;
+#else
+       *pval = vcpu->irr[1];
+       return (IA64_NO_FAULT);
+#endif
+}
+
+IA64FAULT vcpu_get_irr2(VCPU *vcpu, UINT64 *pval)
+{
+#ifndef IRR_USE_FIXED
+       printk("vcpu_get_irr: called, not implemented yet\n");
+       return IA64_ILLOP_FAULT;
+#else
+       *pval = vcpu->irr[2];
+       return (IA64_NO_FAULT);
+#endif
+}
+
+IA64FAULT vcpu_get_irr3(VCPU *vcpu, UINT64 *pval)
+{
+#ifndef IRR_USE_FIXED
+       printk("vcpu_get_irr: called, not implemented yet\n");
+       return IA64_ILLOP_FAULT;
+#else
+       *pval = vcpu->irr[3];
+       return (IA64_NO_FAULT);
+#endif
+}
+
+IA64FAULT vcpu_get_itv(VCPU *vcpu, UINT64 *pval)
+{
+       *pval = PSCB(vcpu).itv;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_pmv(VCPU *vcpu, UINT64 *pval)
+{
+       *pval = PSCB(vcpu).pmv;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_cmcv(VCPU *vcpu, UINT64 *pval)
+{
+       *pval = PSCB(vcpu).cmcv;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_lrr0(VCPU *vcpu, UINT64 *pval)
+{
+       // fix this when setting values other than m-bit is supported
+       printf("vcpu_get_lrr0: Unmasked interrupts unsupported\n");
+       *pval = (1L << 16);
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_lrr1(VCPU *vcpu, UINT64 *pval)
+{
+       // fix this when setting values other than m-bit is supported
+       printf("vcpu_get_lrr1: Unmasked interrupts unsupported\n");
+       *pval = (1L << 16);
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_lid(VCPU *vcpu, UINT64 val)
+{
+       printf("vcpu_set_lid: Setting cr.lid is unsupported\n");
+       return (IA64_ILLOP_FAULT);
+}
+
+IA64FAULT vcpu_set_tpr(VCPU *vcpu, UINT64 val)
+{
+       if (val & 0xff00) return IA64_RSVDREG_FAULT;
+       PSCB(vcpu).tpr = val;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_eoi(VCPU *vcpu, UINT64 val)
+{
+       UINT64 *p, bits, vec, bitnum;
+       int i;
+
+       p = &PSCB(vcpu).insvc[3];
+       for (i = 3; (i >= 0) && !(bits = *p); i--, p--);
+       if (i < 0) {
+               printf("Trying to EOI interrupt when none are in-service.\r\n");
+               return;
+       }
+       bitnum = ia64_fls(bits);
+       vec = bitnum + (i*64);
+       /* clear the correct bit */
+       bits &= ~(1L << bitnum);
+       *p = bits;
+       /* clearing an eoi bit may unmask another pending interrupt... */
+       if (PSCB(vcpu).interrupt_delivery_enabled) { // but only if enabled...
+               // worry about this later... Linux only calls eoi
+               // with interrupts disabled
+               printf("Trying to EOI interrupt with interrupts enabled\r\n");
+       }
+//printf("YYYYY vcpu_set_eoi: Successful\n");
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_lrr0(VCPU *vcpu, UINT64 val)
+{
+       if (!(val & (1L << 16))) {
+               printf("vcpu_set_lrr0: Unmasked interrupts unsupported\n");
+               return (IA64_ILLOP_FAULT);
+       }
+       // no place to save this state but nothing to do anyway
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_lrr1(VCPU *vcpu, UINT64 val)
+{
+       if (!(val & (1L << 16))) {
+               printf("vcpu_set_lrr0: Unmasked interrupts unsupported\n");
+               return (IA64_ILLOP_FAULT);
+       }
+       // no place to save this state but nothing to do anyway
+       return (IA64_NO_FAULT);
+}
+
+
+IA64FAULT vcpu_set_itv(VCPU *vcpu, UINT64 val)
+{
+extern unsigned long privop_trace;
+//privop_trace=1;
+       if (val & 0xef00) return (IA64_ILLOP_FAULT);
+       PSCB(vcpu).itv = val;
+       if (val & 0x10000) {
+printf("**** vcpu_set_itv(%d): vitm=%lx, setting to 0\n",val,PSCB(vcpu).domain_itm);
+               PSCB(vcpu).domain_itm = 0;
+       }
+       else vcpu_enable_timer(vcpu,1000000L);
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_pmv(VCPU *vcpu, UINT64 val)
+{
+       if (val & 0xef00) /* reserved fields */ return IA64_RSVDREG_FAULT;
+       PSCB(vcpu).pmv = val;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_cmcv(VCPU *vcpu, UINT64 val)
+{
+       if (val & 0xef00) /* reserved fields */ return IA64_RSVDREG_FAULT;
+       PSCB(vcpu).cmcv = val;
+       return (IA64_NO_FAULT);
+}
+
+/**************************************************************************
+Interval timer routines
+**************************************************************************/
+
+BOOLEAN vcpu_timer_disabled(VCPU *vcpu)
+{
+       UINT64 itv = PSCB(vcpu).itv;
+       return(!itv || !!(itv & 0x10000));
+}
+
+BOOLEAN vcpu_timer_expired(VCPU *vcpu)
+{
+       unsigned long domain_itm = PSCB(vcpu).domain_itm;
+       unsigned long now = ia64_get_itc();
+       if (domain_itm && (now > domain_itm) &&
+               !vcpu_timer_disabled(vcpu)) return TRUE;
+       return FALSE;
+}
+
+void vcpu_safe_set_itm(unsigned long val)
+{
+       unsigned long epsilon = 100;
+       UINT64 now = ia64_get_itc();
+
+       local_irq_disable();
+       while (1) {
+//printf("*** vcpu_safe_set_itm: Setting itm to %lx, itc=%lx\n",val,now);
+               ia64_set_itm(val);
+               if (val > (now = ia64_get_itc())) break;
+               val = now + epsilon;
+               epsilon <<= 1;
+       }
+       local_irq_enable();
+}
+
+void vcpu_set_next_timer(VCPU *vcpu)
+{
+       UINT64 d = PSCB(vcpu).domain_itm;
+       //UINT64 s = PSCB(vcpu).xen_itm;
+       UINT64 s = local_cpu_data->itm_next;
+       UINT64 now = ia64_get_itc();
+       //UINT64 interval = PSCB(vcpu).xen_timer_interval;
+
+       /* gloss over the wraparound problem for now... we know it exists
+        * but it doesn't matter right now */
+
+#if 0
+       /* ensure at least next SP tick is in the future */
+       if (!interval) PSCB(vcpu).xen_itm = now +
+#if 0
+               (running_on_sim() ? SIM_DEFAULT_CLOCK_RATE :
+                                       DEFAULT_CLOCK_RATE);
+#else
+       3000000;
+//printf("vcpu_set_next_timer: HACK!\n");
+#endif
+#if 0
+       if (PSCB(vcpu).xen_itm < now)
+               while (PSCB(vcpu).xen_itm < now + (interval>>1))
+                       PSCB(vcpu).xen_itm += interval;
+#endif
+#endif
+
+       if (is_idle_task(vcpu)) {
+               printf("****** vcpu_set_next_timer called during idle!!\n");
+       }
+       //s = PSCB(vcpu).xen_itm;
+       if (d && (d > now) && (d < s)) {
+               vcpu_safe_set_itm(d);
+               //using_domain_as_itm++;
+       }
+       else {
+               vcpu_safe_set_itm(s);
+               //using_xen_as_itm++;
+       }
+}
+
+// parameter is a time interval specified in cycles
+void vcpu_enable_timer(VCPU *vcpu,UINT64 cycles)
+{
+    PSCB(vcpu).xen_timer_interval = cycles;
+    vcpu_set_next_timer(vcpu);
+    printf("vcpu_enable_timer(%d): interval set to %d cycles\n",
+             PSCB(vcpu).xen_timer_interval);
+    __set_bit(PSCB(vcpu).itv, PSCB(vcpu).delivery_mask);
+}
+
+IA64FAULT vcpu_set_itm(VCPU *vcpu, UINT64 val)
+{
+       UINT now = ia64_get_itc();
+
+       //if (val < now) val = now + 1000;
+//printf("*** vcpu_set_itm: called with %lx\n",val);
+       PSCB(vcpu).domain_itm = val;
+       vcpu_set_next_timer(vcpu);
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_itc(VCPU *vcpu, UINT64 val)
+{
+       
+       UINT64 oldnow = ia64_get_itc();
+       UINT64 olditm = PSCB(vcpu).domain_itm;
+       unsigned long d = olditm - oldnow;
+       unsigned long x = local_cpu_data->itm_next - oldnow;
+       
+       UINT64 newnow = val, min_delta;
+
+       local_irq_disable();
+       if (olditm) {
+printf("**** vcpu_set_itc(%lx): vitm changed to %lx\n",val,newnow+d);
+               PSCB(vcpu).domain_itm = newnow + d;
+       }
+       local_cpu_data->itm_next = newnow + x;
+       d = PSCB(vcpu).domain_itm;
+       x = local_cpu_data->itm_next;
+       
+       ia64_set_itc(newnow);
+       if (d && (d > newnow) && (d < x)) {
+               vcpu_safe_set_itm(d);
+               //using_domain_as_itm++;
+       }
+       else {
+               vcpu_safe_set_itm(x);
+               //using_xen_as_itm++;
+       }
+       local_irq_enable();
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_itm(VCPU *vcpu, UINT64 *pval)
+{
+       //FIXME: Implement this
+       printf("vcpu_get_itm: Getting cr.itm is unsupported... continuing\n");
+       return (IA64_NO_FAULT);
+       //return (IA64_ILLOP_FAULT);
+}
+
+IA64FAULT vcpu_get_itc(VCPU *vcpu, UINT64 *pval)
+{
+       //TODO: Implement this
+       printf("vcpu_get_itc: Getting ar.itc is unsupported\n");
+       return (IA64_ILLOP_FAULT);
+}
+
+void vcpu_pend_timer(VCPU *vcpu)
+{
+       UINT64 itv = PSCB(vcpu).itv & 0xff;
+
+       if (vcpu_timer_disabled(vcpu)) return;
+       vcpu_pend_interrupt(vcpu, itv);
+}
+
+//FIXME: This is a hack because everything dies if a timer tick is lost
+void vcpu_poke_timer(VCPU *vcpu)
+{
+       UINT64 itv = PSCB(vcpu).itv & 0xff;
+       UINT64 now = ia64_get_itc();
+       UINT64 itm = PSCB(vcpu).domain_itm;
+       UINT64 irr;
+
+       if (vcpu_timer_disabled(vcpu)) return;
+       if (!itm) return;
+       if (itv != 0xefL) {
+               printf("vcpu_poke_timer: unimplemented itv=%lx!\n",itv);
+               while(1);
+       }
+       // using 0xef instead of itv so can get real irr
+       if (now > itm && !test_bit(0xefL, PSCB(vcpu).insvc)) {
+               if (!test_bit(0xefL,PSCB(vcpu).irr)) {
+                       irr = ia64_getreg(_IA64_REG_CR_IRR3);
+                       if (irr & (1L<<(0xef-0xc0))) return;
+if (now-itm>0x800000)
+printf("*** poking timer: now=%lx,vitm=%lx,xitm=%lx,itm=%lx\n",now,itm,local_cpu_data->itm_next,ia64_get_itm());
+                       vcpu_pend_interrupt(vcpu, 0xefL);
+               }
+       }
+}
+
+
+/**************************************************************************
+Privileged operation emulation routines
+**************************************************************************/
+
+IA64FAULT vcpu_force_data_miss(VCPU *vcpu, UINT64 ifa)
+{
+       PSCB(vcpu).ifa = ifa;   // privop traps don't set ifa so do it here
+       return (IA64_DATA_TLB_VECTOR | IA64_FORCED_IFA);
+}
+
+
+IA64FAULT vcpu_rfi(VCPU *vcpu)
+{
+       // TODO: Only allowed for current vcpu
+       PSR psr;
+       UINT64 int_enable, regspsr = 0;
+       UINT64 ifs;
+       REGS *regs = vcpu_regs(vcpu);
+       extern void dorfirfi(void);
+
+       psr.i64 = PSCB(vcpu).ipsr;
+       if (psr.cpl < 3) psr.cpl = 2;
+       if (psr.i) PSCB(vcpu).interrupt_delivery_enabled = 1;
+       int_enable = psr.i;
+       if (psr.ic)  PSCB(vcpu).interrupt_collection_enabled = 1;
+       if (psr.dt && psr.rt && psr.it) vcpu_set_metaphysical_mode(vcpu,FALSE);
+       else vcpu_set_metaphysical_mode(vcpu,TRUE);
+       psr.ic = 1; psr.i = 1;
+       psr.dt = 1; psr.rt = 1; psr.it = 1;
+       psr.bn = 1;
+       //psr.pk = 1;  // checking pkeys shouldn't be a problem but seems broken
+       if (psr.be) {
+               printf("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n");
+               return (IA64_ILLOP_FAULT);
+       }
+       PSCB(vcpu).incomplete_regframe = 0; // is this necessary?
+       ifs = PSCB(vcpu).ifs;
+       //if ((ifs & regs->cr_ifs & 0x8000000000000000L) && ifs != regs->cr_ifs) {
+       //if ((ifs & 0x8000000000000000L) && ifs != regs->cr_ifs) {
+       if (ifs & regs->cr_ifs & 0x8000000000000000L) {
+#define SI_OFS(x)      ((char *)(&PSCB(vcpu).x) - (char *)(vcpu->shared_info))
+if (SI_OFS(iip)!=0x150 || SI_OFS(ipsr)!=0x148 || SI_OFS(ifs)!=0x158) {
+printf("SI_CR_IIP/IPSR/IFS_OFFSET CHANGED, SEE dorfirfi\n");
+while(1);
+}
+               // TODO: validate PSCB(vcpu).iip 
+               // TODO: PSCB(vcpu).ipsr = psr;
+               PSCB(vcpu).ipsr = psr.i64;
+               // now set up the trampoline
+               regs->cr_iip = *(unsigned long *)dorfirfi; // function pointer!!
+               __asm__ __volatile ("mov %0=psr;;":"=r"(regspsr)::"memory");
+               regs->cr_ipsr = regspsr & ~(IA64_PSR_I | IA64_PSR_IC | IA64_PSR_BN);
+       }
+       else {
+               regs->cr_ipsr = psr.i64;
+               regs->cr_iip = PSCB(vcpu).iip;
+       }
+       PSCB(vcpu).interrupt_collection_enabled = 1;
+       vcpu_bsw1(vcpu);
+       PSCB(vcpu).interrupt_delivery_enabled = int_enable;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_cover(VCPU *vcpu)
+{
+       REGS *regs = vcpu_regs(vcpu);
+
+       if (!PSCB(vcpu).interrupt_collection_enabled) {
+               if (!PSCB(vcpu).incomplete_regframe)
+                       PSCB(vcpu).ifs = regs->cr_ifs;
+               else PSCB(vcpu).incomplete_regframe = 0;
+       }
+       regs->cr_ifs = 0;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_thash(VCPU *vcpu, UINT64 vadr, UINT64 *pval)
+{
+       extern unsigned long vcpu_get_rr_ps(VCPU *vcpu,UINT64 vadr);
+       UINT64 pta = PSCB(vcpu).pta;
+       UINT64 pta_sz = (pta & IA64_PTA_SZ(0x3f)) >> IA64_PTA_SZ_BIT;
+       UINT64 pta_base = pta & ~((1UL << IA64_PTA_BASE_BIT)-1);
+       UINT64 Mask = (1L << pta_sz) - 1;
+       UINT64 Mask_60_15 = (Mask >> 15) & 0x3fffffffffff;
+       UINT64 compMask_60_15 = ~Mask_60_15;
+       //UINT64 rr_ps = RR_TO_PS(get_rr(vadr));
+       UINT64 rr_ps = vcpu_get_rr_ps(vcpu,vadr);
+       UINT64 VHPT_offset = (vadr >> rr_ps) << 3;
+       UINT64 VHPT_addr1 = vadr & 0xe000000000000000L;
+       UINT64 VHPT_addr2a =
+               ((pta_base >> 15) & 0x3fffffffffff) & compMask_60_15;
+       UINT64 VHPT_addr2b =
+               ((VHPT_offset >> 15) & 0x3fffffffffff) & Mask_60_15;;
+       UINT64 VHPT_addr3 = VHPT_offset & 0x3fff;
+       UINT64 VHPT_addr = VHPT_addr1 | ((VHPT_addr2a | VHPT_addr2b) << 15) |
+                       VHPT_addr3;
+
+       if (VHPT_addr1 == 0xe000000000000000L) {
+           printf("vcpu_thash: thash unsupported with rr7 @%lx\n",
+               PSCB(vcpu).iip);
+           return (IA64_ILLOP_FAULT);
+       }
+//verbose("vcpu_thash: vadr=%p, VHPT_addr=%p\n",vadr,VHPT_addr);
+       *pval = VHPT_addr;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *padr)
+{
+       printf("vcpu_ttag: ttag instruction unsupported\n");
+       return (IA64_ILLOP_FAULT);
+}
+
+IA64FAULT vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr)
+{
+       extern TR_ENTRY *match_tr(VCPU *,UINT64);
+       extern TR_ENTRY *match_dtlb(VCPU *,UINT64);
+       TR_ENTRY *trp;
+       UINT64 mask;
+
+extern unsigned long privop_trace;
+       if ((trp=match_tr(current,vadr)) || (trp=match_dtlb(current,vadr))) {
+               mask = (1L << trp->ps) - 1;
+               *padr = ((trp->ppn << 12) & ~mask) | (vadr & mask);
+               verbose("vcpu_tpa: addr=%p @%p, successful, padr=%p\n",vadr,PSCB(vcpu).iip,*padr);
+               return (IA64_NO_FAULT);
+       }
+       verbose("vcpu_tpa addr=%p, @%p, forcing data miss\n",vadr,PSCB(vcpu).iip);
+       return vcpu_force_data_miss(vcpu, vadr);
+}
+
+IA64FAULT vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key)
+{
+       printf("vcpu_tak: tak instruction unsupported\n");
+       return (IA64_ILLOP_FAULT);
+       // HACK ALERT: tak does a thash for now
+       //return vcpu_thash(vcpu,vadr,key);
+}
+
+/**************************************************************************
+ VCPU debug breakpoint register access routines
+**************************************************************************/
+
+IA64FAULT vcpu_set_dbr(VCPU *vcpu, UINT64 reg, UINT64 val)
+{
+       // TODO: unimplemented DBRs return a reserved register fault
+       // TODO: Should set Logical CPU state, not just physical
+       ia64_set_dbr(reg,val);
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_ibr(VCPU *vcpu, UINT64 reg, UINT64 val)
+{
+       // TODO: unimplemented IBRs return a reserved register fault
+       // TODO: Should set Logical CPU state, not just physical
+       ia64_set_ibr(reg,val);
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_dbr(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+{
+       // TODO: unimplemented DBRs return a reserved register fault
+       UINT64 val = ia64_get_dbr(reg);
+       *pval = val;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_ibr(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+{
+       // TODO: unimplemented IBRs return a reserved register fault
+       UINT64 val = ia64_get_ibr(reg);
+       *pval = val;
+       return (IA64_NO_FAULT);
+}
+
+/**************************************************************************
+ VCPU performance monitor register access routines
+**************************************************************************/
+
+IA64FAULT vcpu_set_pmc(VCPU *vcpu, UINT64 reg, UINT64 val)
+{
+       // TODO: Should set Logical CPU state, not just physical
+       // NOTE: Writes to unimplemented PMC registers are discarded
+       ia64_set_pmc(reg,val);
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_set_pmd(VCPU *vcpu, UINT64 reg, UINT64 val)
+{
+       // TODO: Should set Logical CPU state, not just physical
+       // NOTE: Writes to unimplemented PMD registers are discarded
+       ia64_set_pmd(reg,val);
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_pmc(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+{
+       // NOTE: Reads from unimplemented PMC registers return zero
+       UINT64 val = (UINT64)ia64_get_pmc(reg);
+       *pval = val;
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_pmd(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+{
+       // NOTE: Reads from unimplemented PMD registers return zero
+       UINT64 val = (UINT64)ia64_get_pmd(reg);
+       *pval = val;
+       return (IA64_NO_FAULT);
+}
+
+/**************************************************************************
+ VCPU banked general register access routines
+**************************************************************************/
+
+IA64FAULT vcpu_bsw0(VCPU *vcpu)
+{
+       REGS *regs = vcpu_regs(vcpu);
+       unsigned long *r = &regs->r16;
+       unsigned long *b0 = &PSCB(vcpu).bank0_regs[0];
+       unsigned long *b1 = &PSCB(vcpu).bank1_regs[0];
+       int i;
+
+       if (PSCB(vcpu).banknum) {
+               for (i = 0; i < 16; i++) { *b1++ = *r; *r++ = *b0++; }
+               PSCB(vcpu).banknum = 0;
+       }
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_bsw1(VCPU *vcpu)
+{
+       REGS *regs = vcpu_regs(vcpu);
+       unsigned long *r = &regs->r16;
+       unsigned long *b0 = &PSCB(vcpu).bank0_regs[0];
+       unsigned long *b1 = &PSCB(vcpu).bank1_regs[0];
+       int i;
+
+       if (!PSCB(vcpu).banknum) {
+               for (i = 0; i < 16; i++) { *b0++ = *r; *r++ = *b1++; }
+               PSCB(vcpu).banknum = 1;
+       }
+       return (IA64_NO_FAULT);
+}
+
+/**************************************************************************
+ VCPU cpuid access routines
+**************************************************************************/
+
+
+IA64FAULT vcpu_get_cpuid(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+{
+       // FIXME: This could get called as a result of a rsvd-reg fault
+       // if reg > 3
+       switch(reg) {
+           case 0:
+           case 1:
+               memcpy(pval,"Xen/ia64",8);
+               break;
+           case 2:
+               *pval = 0;
+               break;
+           case 3:
+               *pval = 0;  //FIXME: See vol1, 3.1.11
+               break;
+           case 4:
+               *pval = 1;  //FIXME: See vol1, 3.1.11
+               break;
+           default:
+               *pval = 0;  //FIXME: See vol1, 3.1.11
+               break;
+       }
+       return (IA64_NO_FAULT);
+}
+
+/**************************************************************************
+ VCPU region register access routines
+**************************************************************************/
+
+unsigned long vcpu_get_rr_ve(VCPU *vcpu,UINT64 vadr)
+{
+       
+       ia64_rr rr;
+
+       rr.rrval = PSCB(vcpu).rrs[vadr>>61];
+       return(rr.ve);
+}
+
+
+unsigned long vcpu_get_rr_ps(VCPU *vcpu,UINT64 vadr)
+{
+       
+       ia64_rr rr;
+
+       rr.rrval = PSCB(vcpu).rrs[vadr>>61];
+       return(rr.ps);
+}
+
+
+unsigned long vcpu_get_rr_rid(VCPU *vcpu,UINT64 vadr)
+{
+       
+       ia64_rr rr;
+
+       rr.rrval = PSCB(vcpu).rrs[vadr>>61];
+       return(rr.rid);
+}
+
+
+IA64FAULT vcpu_set_rr(VCPU *vcpu, UINT64 reg, UINT64 val)
+{
+       extern void set_one_rr(UINT64, UINT64);
+       PSCB(vcpu).rrs[reg>>61] = val;
+       // warning: set_one_rr() does it "live"
+       set_one_rr(reg,val);
+       return (IA64_NO_FAULT);
+}
+
+IA64FAULT vcpu_get_rr(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+{
+       UINT val = PSCB(vcpu).rrs[reg>>61];
+       *pval = val;
+       return (IA64_NO_FAULT);
+}
+
+/**************************************************************************
+ VCPU protection key register access routines
+**************************************************************************/
+
+IA64FAULT vcpu_get_pkr(VCPU *vcpu, UINT64 reg, UINT64 *pval)
+{
+#ifndef PKR_USE_FIXED
+       printk("vcpu_get_pkr: called, not implemented yet\n");
+       return IA64_ILLOP_FAULT;
+#else
+       UINT64 val = (UINT64)ia64_get_pkr(reg);
+       *pval = val;
+       return (IA64_NO_FAULT);
+#endif
+}
+
+IA64FAULT vcpu_set_pkr(VCPU *vcpu, UINT64 reg, UINT64 val)
+{
+#ifndef PKR_USE_FIXED
+       printk("vcpu_set_pkr: called, not implemented yet\n");
+       return IA64_ILLOP_FAULT;
+#else
+//     if (reg >= NPKRS) return (IA64_ILLOP_FAULT);
+       vcpu->pkrs[reg] = val;
+       ia64_set_pkr(reg,val);
+       return (IA64_NO_FAULT);
+#endif
+}
+
+/**************************************************************************
+ VCPU translation register access routines
+**************************************************************************/
+
+static void vcpu_purge_tr_entry(TR_ENTRY *trp)
+{
+       trp->p = 0;
+}
+
+static void vcpu_set_tr_entry(TR_ENTRY *trp, UINT64 pte, UINT64 itir, UINT64 ifa)
+{
+       UINT64 ps;
+
+       trp->itir = itir;
+       trp->rid = virtualize_rid(current, get_rr(ifa) & RR_RID_MASK);
+       trp->p = 1;
+       ps = trp->ps;
+       trp->page_flags = pte;
+       if (trp->pl < 2) trp->pl = 2;
+       trp->vadr = ifa & ~0xfff;
+       if (ps > 12) { // "ignore" relevant low-order bits
+               trp->ppn &= ~((1UL<<(ps-12))-1);
+               trp->vadr &= ~((1UL<<ps)-1);
+       }
+}
+
+TR_ENTRY *vcpu_match_tr_entry(VCPU *vcpu, TR_ENTRY *trp, UINT64 ifa, int count)
+{
+       unsigned long rid = (get_rr(ifa) & RR_RID_MASK);
+       int i;
+
+       for (i = 0; i < count; i++, trp++) {
+               if (!trp->p) continue;
+               if (physicalize_rid(vcpu,trp->rid) != rid) continue;
+               if (ifa < trp->vadr) continue;
+               if (ifa >= (trp->vadr + (1L << trp->ps)) - 1) continue;
+               //if (trp->key && !match_pkr(vcpu,trp->key)) continue;
+               return trp;
+       }
+       return 0;
+}
+
+TR_ENTRY *match_tr(VCPU *vcpu, unsigned long ifa)
+{
+       TR_ENTRY *trp;
+
+       trp = vcpu_match_tr_entry(vcpu,vcpu->shared_info->arch.dtrs,ifa,NDTRS);
+       if (trp) return trp;
+       trp = vcpu_match_tr_entry(vcpu,vcpu->shared_info->arch.itrs,ifa,NITRS);
+       if (trp) return trp;
+       return 0;
+}
+
+IA64FAULT vcpu_itr_d(VCPU *vcpu, UINT64 slot, UINT64 pte,
+               UINT64 itir, UINT64 ifa)
+{
+       TR_ENTRY *trp;
+
+       if (slot >= NDTRS) return IA64_RSVDREG_FAULT;
+       trp = &PSCB(vcpu).dtrs[slot];
+       vcpu_set_tr_entry(trp,pte,itir,ifa);
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_itr_i(VCPU *vcpu, UINT64 slot, UINT64 pte,
+               UINT64 itir, UINT64 ifa)
+{
+       TR_ENTRY *trp;
+
+       if (slot >= NITRS) return IA64_RSVDREG_FAULT;
+       trp = &PSCB(vcpu).itrs[slot];
+       vcpu_set_tr_entry(trp,pte,itir,ifa);
+       return IA64_NO_FAULT;
+}
+
+/**************************************************************************
+ VCPU translation cache access routines
+**************************************************************************/
+
+void foobar(void) { /*vcpu_verbose = 1;*/ }
+
+extern VCPU *dom0;
+
+void vcpu_itc_no_srlz(VCPU *vcpu, UINT64 IorD, UINT64 vaddr, UINT64 pte, UINT64 logps)
+{
+       unsigned long psr;
+       unsigned long ps = (vcpu==dom0) ? logps : PAGE_SHIFT;
+
+       // FIXME: validate ifa here (not in Xen space), COULD MACHINE CHECK!
+       // FIXME, must be inlined or potential for nested fault here!
+       psr = ia64_clear_ic();
+       ia64_itc(IorD,vaddr,pte,ps); // FIXME: look for bigger mappings
+       ia64_set_psr(psr);
+       // ia64_srlz_i(); // no srls req'd, will rfi later
+       if (IorD & 0x1) vcpu_set_tr_entry(&PSCB(vcpu).itlb,pte,logps<<2,vaddr);
+       if (IorD & 0x2) vcpu_set_tr_entry(&PSCB(vcpu).dtlb,pte,logps<<2,vaddr);
+}
+
+TR_ENTRY *match_dtlb(VCPU *vcpu, unsigned long ifa)
+{
+       return vcpu_match_tr_entry(vcpu,&vcpu->shared_info->arch.dtlb,ifa,1);
+}
+
+IA64FAULT vcpu_itc_d(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa)
+{
+       unsigned long pteval, logps = (itir >> 2) & 0x3f;
+       unsigned long translate_domain_pte(UINT64,UINT64,UINT64);
+
+       if (((itir & ~0xfc) >> 2) < PAGE_SHIFT) {
+               printf("vcpu_itc_d: domain trying to use smaller page size!\n");
+               //FIXME: kill domain here
+               while(1);
+       }
+       //itir = (itir & ~0xfc) | (PAGE_SHIFT<<2); // ignore domain's pagesize
+       pteval = translate_domain_pte(pte,ifa,itir);
+       if (!pteval) return IA64_ILLOP_FAULT;
+       vcpu_itc_no_srlz(vcpu,2,ifa,pteval,logps);
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_itc_i(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa)
+{
+       unsigned long pteval, logps = (itir >> 2) & 0x3f;
+       unsigned long translate_domain_pte(UINT64,UINT64,UINT64);
+
+       // FIXME: validate ifa here (not in Xen space), COULD MACHINE CHECK!
+       if (((itir & ~0xfc) >> 2) < PAGE_SHIFT) {
+               printf("vcpu_itc_i: domain trying to use smaller page size!\n");
+               //FIXME: kill domain here
+               while(1);
+       }
+       //itir = (itir & ~0xfc) | (PAGE_SHIFT<<2); // ignore domain's pagesize
+       pteval = translate_domain_pte(pte,ifa,itir);
+       // FIXME: what to do if bad physical address? (machine check?)
+       if (!pteval) return IA64_ILLOP_FAULT;
+       vcpu_itc_no_srlz(vcpu, 1,ifa,pteval,logps);
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_ptc_l(VCPU *vcpu, UINT64 vadr, UINT64 addr_range)
+{
+       printk("vcpu_ptc_l: called, not implemented yet\n");
+       return IA64_ILLOP_FAULT;
+}
+
+IA64FAULT vcpu_fc(VCPU *vcpu, UINT64 vadr)
+{
+       UINT64 mpaddr;
+       IA64FAULT fault;
+       unsigned long lookup_domain_mpa(VCPU *,unsigned long);
+       unsigned long pteval, dom_imva;
+
+       fault = vcpu_tpa(vcpu, vadr, &mpaddr);
+       if (fault == IA64_NO_FAULT) {
+               struct domain *dom0;
+               unsigned long dom0_start, dom0_size;
+               if (vcpu == dom0) {
+                       if (mpaddr < dom0_start || mpaddr >= dom0_start + dom0_size) {
+                               printk("vcpu_fc: bad dom0 mpaddr %p!\n",mpaddr);
+                       }
+               }
+               pteval = lookup_domain_mpa(vcpu,mpaddr);
+               if (pteval) {
+                       dom_imva = __va(pteval & _PFN_MASK);
+                       ia64_fc(dom_imva);
+               }
+               else {
+                       REGS *regs = vcpu_regs(vcpu);
+                       printk("vcpu_fc: can't flush vadr=%p, iip=%p\n",
+                                       vadr,regs->cr_iip);
+               }
+       }
+       return fault;
+}
+
+IA64FAULT vcpu_ptc_e(VCPU *vcpu, UINT64 vadr)
+{
+
+       // Note that this only needs to be called once, i.e. the
+       // architected loop to purge the entire TLB, should use
+       //  base = stride1 = stride2 = 0, count0 = count 1 = 1
+
+       // FIXME: When VHPT is in place, flush that too!
+       local_flush_tlb_all();
+       // just invalidate the "whole" tlb
+       vcpu_purge_tr_entry(&PSCB(vcpu).dtlb);
+       vcpu_purge_tr_entry(&PSCB(vcpu).itlb);
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_ptc_g(VCPU *vcpu, UINT64 vadr, UINT64 addr_range)
+{
+       printk("vcpu_ptc_g: called, not implemented yet\n");
+       return IA64_ILLOP_FAULT;
+}
+
+IA64FAULT vcpu_ptc_ga(VCPU *vcpu,UINT64 vadr,UINT64 addr_range)
+{
+       extern ia64_global_tlb_purge(UINT64 start, UINT64 end, UINT64 nbits);
+       // FIXME: validate not flushing Xen addresses
+       // if (Xen address) return(IA64_ILLOP_FAULT);
+       // FIXME: ??breaks if domain PAGE_SIZE < Xen PAGE_SIZE
+       ia64_global_tlb_purge(vadr,vadr+addr_range,PAGE_SHIFT);
+       vcpu_purge_tr_entry(&PSCB(vcpu).dtlb);
+       vcpu_purge_tr_entry(&PSCB(vcpu).itlb);
+       return IA64_NO_FAULT;
+}
+
+IA64FAULT vcpu_ptr_d(VCPU *vcpu,UINT64 vadr,UINT64 addr_range)
+{
+       printf("vcpu_ptr_d: Purging TLB is unsupported\n");
+       return (IA64_ILLOP_FAULT);
+}
+
+IA64FAULT vcpu_ptr_i(VCPU *vcpu,UINT64 vadr,UINT64 addr_range)
+{
+       printf("vcpu_ptr_i: Purging TLB is unsupported\n");
+       return (IA64_ILLOP_FAULT);
+}
+
+void vcpu_set_regs(VCPU *vcpu, REGS *regs)
+{
+       vcpu->regs = regs;
+}
diff --git a/xen/arch/ia64/xenasm.S b/xen/arch/ia64/xenasm.S
new file mode 100644 (file)
index 0000000..8616e07
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * Assembly support routines for Xen/ia64
+ *
+ * Copyright (C) 2004 Hewlett-Packard Co
+ *     Dan Magenheimer <dan.magenheimer@hp.com>
+ */
+
+#include <linux/config.h>
+#include <asm/asmmacro.h>
+#include <asm/processor.h>
+#include <asm/pgtable.h>
+#include <asm/vhpt.h>
+
+#define RunningOnHpSki(rx,ry,pn)                       \
+       addl rx = 2, r0;                                \
+       addl ry = 3, r0;                                \
+       ;;                                              \
+       mov rx = cpuid[rx];                             \
+       mov ry = cpuid[ry];                             \
+       ;;                                              \
+       cmp.eq pn,p0 = 0, rx;                           \
+       ;;                                              \
+       (pn) movl rx = 0x7000004 ;                      \
+       ;;                                              \
+       (pn) cmp.eq pn,p0 = ry, rx;                     \
+       ;;
+
+//int platform_is_hp_ski(void)
+GLOBAL_ENTRY(platform_is_hp_ski)
+       mov r8 = 0
+       RunningOnHpSki(r3,r9,p8)
+(p8)   mov r8 = 1
+       br.ret.sptk.many b0
+END(platform_is_hp_ski)
+
+// Change rr7 to the passed value while ensuring
+// Xen is mapped into the new region
+#define PSR_BITS_TO_CLEAR                                              \
+       (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_RT |         \
+        IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED |        \
+        IA64_PSR_DFL | IA64_PSR_DFH)
+// FIXME? Note that this turns off the DB bit (debug)
+#define PSR_BITS_TO_SET        IA64_PSR_BN
+
+GLOBAL_ENTRY(ia64_new_rr7)
+       // not sure this unwind statement is correct...
+       .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(1)
+       alloc loc1 = ar.pfs, 1, 7, 0, 0
+1:     {
+         mov r28  = in0                // copy procedure index
+         mov r8   = ip                 // save ip to compute branch
+         mov loc0 = rp                 // save rp
+       };;
+       .body
+       movl loc2=PERCPU_ADDR
+       ;;
+       tpa loc2=loc2                   // grab this BEFORE changing rr7
+       ;;
+#if VHPT_ENABLED
+       movl loc6=VHPT_ADDR
+       ;;
+       tpa loc6=loc6                   // grab this BEFORE changing rr7
+       ;;
+#endif
+       movl loc5=SHAREDINFO_ADDR
+       ;;
+       tpa loc5=loc5                   // grab this BEFORE changing rr7
+       ;;
+       mov loc3 = psr                  // save psr
+       adds r8  = 1f-1b,r8             // calculate return address for call
+       ;;
+       tpa r8=r8                       // convert rp to physical
+       ;;
+       mov loc4=ar.rsc                 // save RSE configuration
+       ;;
+       mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
+       movl r16=PSR_BITS_TO_CLEAR
+       movl r17=PSR_BITS_TO_SET
+       ;;
+       or loc3=loc3,r17                // add in psr the bits to set
+       ;;
+       andcm r16=loc3,r16              // removes bits to clear from psr
+       br.call.sptk.many rp=ia64_switch_mode_phys
+1:
+       // now in physical mode with psr.i/ic off so do rr7 switch
+       dep     r16=-1,r0,61,3
+       ;;
+       mov     rr[r16]=in0
+       srlz.d
+       ;;
+
+       // re-pin mappings for kernel text and data
+       mov r18=KERNEL_TR_PAGE_SHIFT<<2
+       movl r17=KERNEL_START
+       ;;
+       rsm psr.i | psr.ic
+       ;;
+       srlz.i
+       ;;
+       ptr.i   r17,r18
+       ptr.d   r17,r18
+       ;;
+       mov cr.itir=r18
+       mov cr.ifa=r17
+       mov r16=IA64_TR_KERNEL
+       //mov r3=ip
+       movl r18=PAGE_KERNEL
+       ;;
+       dep r2=0,r3,0,KERNEL_TR_PAGE_SHIFT
+       ;;
+       or r18=r2,r18
+       ;;
+       srlz.i
+       ;;
+       itr.i itr[r16]=r18
+       ;;
+       itr.d dtr[r16]=r18
+       ;;
+
+       // re-pin mappings for stack (current), per-cpu, vhpt, and shared info
+
+       // unless overlaps with KERNEL_TR
+       dep r18=0,r13,0,KERNEL_TR_PAGE_SHIFT
+       ;;
+       cmp.eq p7,p0=r17,r18
+(p7)   br.cond.sptk    .stack_overlaps
+       ;;
+       movl r25=PAGE_KERNEL
+       dep r20=0,r13,50,14             // physical address of "current"
+       ;;
+       or r23=r25,r20                  // construct PA | page properties
+       mov r25=IA64_GRANULE_SHIFT<<2
+       ;;
+       ptr.d   r13,r25
+       ;;
+       mov cr.itir=r25
+       mov cr.ifa=r13                  // VA of next task...
+       ;;
+       mov r25=IA64_TR_CURRENT_STACK
+       ;;
+       itr.d dtr[r25]=r23              // wire in new mapping...
+       ;;
+.stack_overlaps:
+
+       movl r22=PERCPU_ADDR
+       ;;
+       movl r25=PAGE_KERNEL
+       ;;
+       mov r20=loc2                    // saved percpu physical address
+       ;;
+       or r23=r25,r20                  // construct PA | page properties
+       mov r24=PERCPU_PAGE_SHIFT<<2
+       ;;
+       ptr.d   r22,r24
+       ;;
+       mov cr.itir=r24
+       mov cr.ifa=r22
+       ;;
+       mov r25=IA64_TR_PERCPU_DATA
+       ;;
+       itr.d dtr[r25]=r23              // wire in new mapping...
+       ;;
+
+#if VHPT_ENABLED
+       movl r22=VHPT_ADDR
+       ;;
+       movl r25=PAGE_KERNEL
+       ;;
+       mov r20=loc6                    // saved vhpt physical address
+       ;;
+       or r23=r25,r20                  // construct PA | page properties
+       mov r24=VHPT_PAGE_SHIFT<<2
+       ;;
+       ptr.d   r22,r24
+       ;;
+       mov cr.itir=r24
+       mov cr.ifa=r22
+       ;;
+       mov r25=IA64_TR_VHPT
+       ;;
+       itr.d dtr[r25]=r23              // wire in new mapping...
+       ;;
+#endif
+
+       movl r22=SHAREDINFO_ADDR
+       ;;
+       movl r25=PAGE_KERNEL
+       ;;
+       mov r20=loc5                    // saved sharedinfo physical address
+       ;;
+       or r23=r25,r20                  // construct PA | page properties
+       mov r24=PAGE_SHIFT<<2
+       ;;
+       ptr.d   r22,r24
+       ;;
+       mov cr.itir=r24
+       mov cr.ifa=r22
+       ;;
+       mov r25=IA64_TR_SHARED_INFO
+       ;;
+       itr.d dtr[r25]=r23              // wire in new mapping...
+       ;;
+
+       // done, switch back to virtual and return
+       mov r16=loc3                    // r16= original psr
+       br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
+       mov psr.l = loc3                // restore init PSR
+
+       mov ar.pfs = loc1
+       mov rp = loc0
+       ;;
+       mov ar.rsc=loc4                 // restore RSE configuration
+       srlz.d                          // seralize restoration of psr.l
+       br.ret.sptk.many rp
+END(ia64_new_rr7)
+
+#include "minstate.h"
+
+GLOBAL_ENTRY(ia64_prepare_handle_privop)
+       .prologue
+       /*
+        * r16 = fake ar.pfs, we simply need to make sure privilege is still 0
+        */
+       mov r16=r0
+       DO_SAVE_SWITCH_STACK
+       br.call.sptk.many rp=ia64_handle_privop         // stack frame setup in ivt
+.ret22:        .body
+       DO_LOAD_SWITCH_STACK
+       br.cond.sptk.many rp                            // goes to ia64_leave_kernel
+END(ia64_prepare_handle_privop)
+
+GLOBAL_ENTRY(ia64_prepare_handle_break)
+       .prologue
+       /*
+        * r16 = fake ar.pfs, we simply need to make sure privilege is still 0
+        */
+       mov r16=r0
+       DO_SAVE_SWITCH_STACK
+       br.call.sptk.many rp=ia64_handle_break  // stack frame setup in ivt
+.ret23:        .body
+       DO_LOAD_SWITCH_STACK
+       br.cond.sptk.many rp                    // goes to ia64_leave_kernel
+END(ia64_prepare_handle_break)
+
+GLOBAL_ENTRY(ia64_prepare_handle_reflection)
+       .prologue
+       /*
+        * r16 = fake ar.pfs, we simply need to make sure privilege is still 0
+        */
+       mov r16=r0
+       DO_SAVE_SWITCH_STACK
+       br.call.sptk.many rp=ia64_handle_reflection     // stack frame setup in ivt
+.ret24:        .body
+       DO_LOAD_SWITCH_STACK
+       br.cond.sptk.many rp                    // goes to ia64_leave_kernel
+END(ia64_prepare_handle_reflection)
+
+// NOTE: instruction spacing must be explicit for recovery on miss
+GLOBAL_ENTRY(__get_domain_bundle)
+       ld8 r8=[r32],8
+       nop 0
+       nop 0
+       ;;
+       ld8 r9=[r32]
+       nop 0
+       nop 0
+       ;;
+       br.ret.sptk.many rp
+       nop 0
+       nop 0
+       ;;
+END(__get_domain_bundle)
+
+GLOBAL_ENTRY(dorfirfi)
+#define SI_CR_IIP_OFFSET 0x150
+#define SI_CR_IPSR_OFFSET 0x148
+#define SI_CR_IFS_OFFSET 0x158
+        movl r16 = SHAREDINFO_ADDR+SI_CR_IIP_OFFSET
+        movl r17 = SHAREDINFO_ADDR+SI_CR_IPSR_OFFSET
+        movl r18 = SHAREDINFO_ADDR+SI_CR_IFS_OFFSET
+       ;;
+       ld8 r16 = [r16]
+       ld8 r17 = [r17]
+       ld8 r18 = [r18]
+       ;;
+        mov cr.iip=r16
+        mov cr.ipsr=r17
+        mov cr.ifs=r18
+       ;;
+        // fall through
+END(dorfirfi)
+
+GLOBAL_ENTRY(dorfi)
+        rfi
+       ;;
+END(dorfirfi)
+
+//
+// Long's Peak UART Offsets
+//
+#define COM_TOP 0xff5e0000
+#define COM_BOT 0xff5e2000
+
+// UART offsets        
+#define UART_TX                0       /* Out: Transmit buffer (DLAB=0) */
+#define UART_INT_ENB   1       /* interrupt enable (DLAB=0) */ 
+#define UART_INT_ID    2       /* Interrupt ID register */
+#define UART_LINE_CTL  3       /* Line control register */
+#define UART_MODEM_CTL 4       /* Modem Control Register */
+#define UART_LSR       5       /* In:  Line Status Register */
+#define UART_MSR       6       /* Modem status register */     
+#define UART_DLATCH_LOW UART_TX
+#define UART_DLATCH_HIGH UART_INT_ENB
+#define COM1   0x3f8
+#define COM2   0x2F8
+#define COM3   0x3E8
+
+/* interrupt enable bits (offset 1) */
+#define DATA_AVAIL_INT 1
+#define XMIT_HOLD_EMPTY_INT 2
+#define LINE_STAT_INT 4
+#define MODEM_STAT_INT 8
+
+/* line status bits (offset 5) */
+#define REC_DATA_READY 1
+#define OVERRUN 2
+#define PARITY_ERROR 4
+#define FRAMING_ERROR 8
+#define BREAK_INTERRUPT 0x10
+#define XMIT_HOLD_EMPTY 0x20
+#define XMIT_SHIFT_EMPTY 0x40
+
+// Write a single character
+// input: r32 = character to be written
+// output: none
+GLOBAL_ENTRY(longs_peak_putc)  
+       rsm psr.dt
+        movl r16 = 0x8000000000000000 + COM_TOP + UART_LSR
+       ;;
+       srlz.i
+       ;;
+
+.Chk_THRE_p:
+        ld1.acq r18=[r16]
+        ;;
+       
+       and r18 = XMIT_HOLD_EMPTY, r18
+       ;;
+       cmp4.eq p6,p0=0,r18
+       ;;
+       
+(p6)    br .Chk_THRE_p
+       ;;
+        movl r16 = 0x8000000000000000 + COM_TOP + UART_TX
+       ;;
+       st1.rel [r16]=r32
+       ;;
+       ssm psr.dt
+       ;;
+       srlz.i
+       ;;
+       br.ret.sptk.many b0
+END(longs_peak_putc)   
+
+/* derived from linux/arch/ia64/hp/sim/boot/boot_head.S */
+GLOBAL_ENTRY(pal_emulator_static)
+       mov r8=-1
+       mov r9=256
+       ;;
+       cmp.gtu p7,p8=r9,r32            /* r32 <= 255? */
+(p7)   br.cond.sptk.few static
+       ;;
+       mov r9=512
+       ;;
+       cmp.gtu p7,p8=r9,r32
+(p7)   br.cond.sptk.few stacked
+       ;;
+static:        cmp.eq p7,p8=6,r32              /* PAL_PTCE_INFO */
+(p8)   br.cond.sptk.few 1f
+       ;;
+       mov r8=0                        /* status = 0 */
+       movl r9=0x100000000             /* tc.base */
+       movl r10=0x0000000200000003     /* count[0], count[1] */
+       movl r11=0x1000000000002000     /* stride[0], stride[1] */
+       br.ret.sptk.few rp
+1:     cmp.eq p7,p8=14,r32             /* PAL_FREQ_RATIOS */
+(p8)   br.cond.sptk.few 1f
+       mov r8=0                        /* status = 0 */
+       movl r9 =0x900000002            /* proc_ratio (1/100) */
+       movl r10=0x100000100            /* bus_ratio<<32 (1/256) */
+       movl r11=0x900000002            /* itc_ratio<<32 (1/100) */
+       ;;
+1:     cmp.eq p7,p8=19,r32             /* PAL_RSE_INFO */
+(p8)   br.cond.sptk.few 1f
+       mov r8=0                        /* status = 0 */
+       mov r9=96                       /* num phys stacked */
+       mov r10=0                       /* hints */
+       mov r11=0
+       br.ret.sptk.few rp
+1:     cmp.eq p7,p8=1,r32              /* PAL_CACHE_FLUSH */
+(p8)   br.cond.sptk.few 1f
+#if 0
+       mov r9=ar.lc
+       movl r8=524288                  /* flush 512k million cache lines (16MB) */
+       ;;
+       mov ar.lc=r8
+       movl r8=0xe000000000000000
+       ;;
+.loop: fc r8
+       add r8=32,r8
+       br.cloop.sptk.few .loop
+       sync.i
+       ;;
+       srlz.i
+       ;;
+       mov ar.lc=r9
+       mov r8=r0
+       ;;
+1:     cmp.eq p7,p8=15,r32             /* PAL_PERF_MON_INFO */
+(p8)   br.cond.sptk.few 1f
+       mov r8=0                        /* status = 0 */
+       movl r9 =0x08122f04             /* generic=4 width=47 retired=8 cycles=18 */
+       mov r10=0                       /* reserved */
+       mov r11=0                       /* reserved */
+       mov r16=0xffff                  /* implemented PMC */
+       mov r17=0x3ffff                 /* implemented PMD */
+       add r18=8,r29                   /* second index */
+       ;;
+       st8 [r29]=r16,16                /* store implemented PMC */
+       st8 [r18]=r0,16                 /* clear remaining bits  */
+       ;;
+       st8 [r29]=r0,16                 /* clear remaining bits  */
+       st8 [r18]=r0,16                 /* clear remaining bits  */
+       ;;
+       st8 [r29]=r17,16                /* store implemented PMD */
+       st8 [r18]=r0,16                 /* clear remaining bits  */
+       mov r16=0xf0                    /* cycles count capable PMC */
+       ;;
+       st8 [r29]=r0,16                 /* clear remaining bits  */
+       st8 [r18]=r0,16                 /* clear remaining bits  */
+       mov r17=0xf0                    /* retired bundles capable PMC */
+       ;;
+       st8 [r29]=r16,16                /* store cycles capable */
+       st8 [r18]=r0,16                 /* clear remaining bits  */
+       ;;
+       st8 [r29]=r0,16                 /* clear remaining bits  */
+       st8 [r18]=r0,16                 /* clear remaining bits  */
+       ;;
+       st8 [r29]=r17,16                /* store retired bundle capable */
+       st8 [r18]=r0,16                 /* clear remaining bits  */
+       ;;
+       st8 [r29]=r0,16                 /* clear remaining bits  */
+       st8 [r18]=r0,16                 /* clear remaining bits  */
+       ;;
+1:     br.cond.sptk.few rp
+#else
+1:
+#endif
+stacked:
+       br.ret.sptk.few rp
+END(pal_emulator_static)